Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / cython / src / Cython / Compiler / Nodes.py
1 #
2 #   Parse tree nodes
3 #
4
5 import cython
6 cython.declare(sys=object, os=object, copy=object,
7                Builtin=object, error=object, warning=object, Naming=object, PyrexTypes=object,
8                py_object_type=object, ModuleScope=object, LocalScope=object, ClosureScope=object,
9                StructOrUnionScope=object, PyClassScope=object,
10                CppClassScope=object, UtilityCode=object, EncodedString=object,
11                absolute_path_length=cython.Py_ssize_t)
12
13 import sys, os, copy
14 from itertools import chain
15
16 import Builtin
17 from Errors import error, warning, InternalError, CompileError
18 import Naming
19 import PyrexTypes
20 import TypeSlots
21 from PyrexTypes import py_object_type, error_type
22 from Symtab import (ModuleScope, LocalScope, ClosureScope,
23     StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope)
24 from Code import UtilityCode
25 from StringEncoding import EncodedString, escape_byte_string, split_string_literal
26 import Options
27 import DebugFlags
28 from Cython.Utils import cached_function
29
30 absolute_path_length = 0
31
32 def relative_position(pos):
33     """
34     We embed the relative filename in the generated C file, since we
35     don't want to have to regenerate and compile all the source code
36     whenever the Python install directory moves (which could happen,
37     e.g,. when distributing binaries.)
38
39     INPUT:
40         a position tuple -- (absolute filename, line number column position)
41
42     OUTPUT:
43         relative filename
44         line number
45
46     AUTHOR: William Stein
47     """
48     global absolute_path_length
49     if absolute_path_length==0:
50         absolute_path_length = len(os.path.abspath(os.getcwd()))
51     return (pos[0].get_filenametable_entry()[absolute_path_length+1:], pos[1])
52
53 def embed_position(pos, docstring):
54     if not Options.embed_pos_in_docstring:
55         return docstring
56     pos_line = u'File: %s (starting at line %s)' % relative_position(pos)
57     if docstring is None:
58         # unicode string
59         return EncodedString(pos_line)
60
61     # make sure we can encode the filename in the docstring encoding
62     # otherwise make the docstring a unicode string
63     encoding = docstring.encoding
64     if encoding is not None:
65         try:
66             pos_line.encode(encoding)
67         except UnicodeEncodeError:
68             encoding = None
69
70     if not docstring:
71         # reuse the string encoding of the original docstring
72         doc = EncodedString(pos_line)
73     else:
74         doc = EncodedString(pos_line + u'\n' + docstring)
75     doc.encoding = encoding
76     return doc
77
78
79 def write_func_call(func, codewriter_class):
80     def f(*args, **kwds):
81         if len(args) > 1 and isinstance(args[1], codewriter_class):
82             # here we annotate the code with this function call
83             # but only if new code is generated
84             node, code = args[:2]
85             marker = '                    /* %s -> %s.%s %s */' % (
86                     ' ' * code.call_level,
87                     node.__class__.__name__,
88                     func.__name__,
89                     node.pos[1:])
90             pristine = code.buffer.stream.tell()
91             code.putln(marker)
92             start = code.buffer.stream.tell()
93             code.call_level += 4
94             res = func(*args, **kwds)
95             code.call_level -= 4
96             if start == code.buffer.stream.tell():
97                 code.buffer.stream.seek(pristine)
98             else:
99                 marker = marker.replace('->', '<-')
100                 code.putln(marker)
101             return res
102         else:
103             return func(*args, **kwds)
104     return f
105
106 class VerboseCodeWriter(type):
107     # Set this as a metaclass to trace function calls in code.
108     # This slows down code generation and makes much larger files.
109     def __new__(cls, name, bases, attrs):
110         from types import FunctionType
111         from Code import CCodeWriter
112         attrs = dict(attrs)
113         for mname, m in attrs.items():
114             if isinstance(m, FunctionType):
115                 attrs[mname] = write_func_call(m, CCodeWriter)
116         return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs)
117
118
119 class CheckAnalysers(type):
120     """Metaclass to check that type analysis functions return a node.
121     """
122     methods = set(['analyse_types',
123                    'analyse_expressions',
124                    'analyse_target_types'])
125
126     def __new__(cls, name, bases, attrs):
127         from types import FunctionType
128         def check(name, func):
129             def call(*args, **kwargs):
130                 retval = func(*args, **kwargs)
131                 if retval is None:
132                     print name, args, kwargs
133                 return retval
134             return call
135
136         attrs = dict(attrs)
137         for mname, m in attrs.items():
138             if isinstance(m, FunctionType) and mname in cls.methods:
139                 attrs[mname] = check(mname, m)
140         return super(CheckAnalysers, cls).__new__(cls, name, bases, attrs)
141
142
143 class Node(object):
144     #  pos         (string, int, int)   Source file position
145     #  is_name     boolean              Is a NameNode
146     #  is_literal  boolean              Is a ConstNode
147
148     #__metaclass__ = CheckAnalysers
149     if DebugFlags.debug_trace_code_generation:
150         __metaclass__ = VerboseCodeWriter
151
152     is_name = 0
153     is_none = 0
154     is_nonecheck = 0
155     is_literal = 0
156     is_terminator = 0
157     temps = None
158
159     # All descendants should set child_attrs to a list of the attributes
160     # containing nodes considered "children" in the tree. Each such attribute
161     # can either contain a single node or a list of nodes. See Visitor.py.
162     child_attrs = None
163
164     cf_state = None
165
166     # This may be an additional (or 'actual') type that will be checked when
167     # this node is coerced to another type. This could be useful to set when
168     # the actual type to which it can coerce is known, but you want to leave
169     # the type a py_object_type
170     coercion_type = None
171
172     def __init__(self, pos, **kw):
173         self.pos = pos
174         self.__dict__.update(kw)
175
176     gil_message = "Operation"
177
178     nogil_check = None
179
180     def gil_error(self, env=None):
181         error(self.pos, "%s not allowed without gil" % self.gil_message)
182
183     cpp_message = "Operation"
184
185     def cpp_check(self, env):
186         if not env.is_cpp():
187             self.cpp_error()
188
189     def cpp_error(self):
190         error(self.pos, "%s only allowed in c++" % self.cpp_message)
191
192     def clone_node(self):
193         """Clone the node. This is defined as a shallow copy, except for member lists
194            amongst the child attributes (from get_child_accessors) which are also
195            copied. Lists containing child nodes are thus seen as a way for the node
196            to hold multiple children directly; the list is not treated as a separate
197            level in the tree."""
198         result = copy.copy(self)
199         for attrname in result.child_attrs:
200             value = getattr(result, attrname)
201             if isinstance(value, list):
202                 setattr(result, attrname, [x for x in value])
203         return result
204
205
206     #
207     #  There are 3 phases of parse tree processing, applied in order to
208     #  all the statements in a given scope-block:
209     #
210     #  (0) analyse_declarations
211     #        Make symbol table entries for all declarations at the current
212     #        level, both explicit (def, cdef, etc.) and implicit (assignment
213     #        to an otherwise undeclared name).
214     #
215     #  (1) analyse_expressions
216     #         Determine the result types of expressions and fill in the
217     #         'type' attribute of each ExprNode. Insert coercion nodes into the
218     #         tree where needed to convert to and from Python objects.
219     #         Allocate temporary locals for intermediate results. Fill
220     #         in the 'result_code' attribute of each ExprNode with a C code
221     #         fragment.
222     #
223     #  (2) generate_code
224     #         Emit C code for all declarations, statements and expressions.
225     #         Recursively applies the 3 processing phases to the bodies of
226     #         functions.
227     #
228
229     def analyse_declarations(self, env):
230         pass
231
232     def analyse_expressions(self, env):
233         raise InternalError("analyse_expressions not implemented for %s" % \
234             self.__class__.__name__)
235
236     def generate_code(self, code):
237         raise InternalError("generate_code not implemented for %s" % \
238             self.__class__.__name__)
239
240     def annotate(self, code):
241         # mro does the wrong thing
242         if isinstance(self, BlockNode):
243             self.body.annotate(code)
244
245     def end_pos(self):
246         try:
247             return self._end_pos
248         except AttributeError:
249             pos = self.pos
250             if not self.child_attrs:
251                 self._end_pos = pos
252                 return pos
253             for attr in self.child_attrs:
254                 child = getattr(self, attr)
255                 # Sometimes lists, sometimes nodes
256                 if child is None:
257                     pass
258                 elif isinstance(child, list):
259                     for c in child:
260                         pos = max(pos, c.end_pos())
261                 else:
262                     pos = max(pos, child.end_pos())
263             self._end_pos = pos
264             return pos
265
266     def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None):
267         """Debug helper method that returns a recursive string representation of this node.
268         """
269         if cutoff == 0:
270             return "<...nesting level cutoff...>"
271         if encountered is None:
272             encountered = set()
273         if id(self) in encountered:
274             return "<%s (0x%x) -- already output>" % (self.__class__.__name__, id(self))
275         encountered.add(id(self))
276
277         def dump_child(x, level):
278             if isinstance(x, Node):
279                 return x.dump(level, filter_out, cutoff-1, encountered)
280             elif isinstance(x, list):
281                 return "[%s]" % ", ".join([dump_child(item, level) for item in x])
282             else:
283                 return repr(x)
284
285
286         attrs = [(key, value) for key, value in self.__dict__.items() if key not in filter_out]
287         if len(attrs) == 0:
288             return "<%s (0x%x)>" % (self.__class__.__name__, id(self))
289         else:
290             indent = "  " * level
291             res = "<%s (0x%x)\n" % (self.__class__.__name__, id(self))
292             for key, value in attrs:
293                 res += "%s  %s: %s\n" % (indent, key, dump_child(value, level + 1))
294             res += "%s>" % indent
295             return res
296
297     def dump_pos(self, mark_column=False, marker='(#)'):
298         """Debug helper method that returns the source code context of this node as a string.
299         """
300         if not self.pos:
301             return u''
302         source_desc, line, col = self.pos
303         contents = source_desc.get_lines(encoding='ASCII',
304                                          error_handling='ignore')
305         # line numbers start at 1
306         lines = contents[max(0,line-3):line]
307         current = lines[-1]
308         if mark_column:
309             current = current[:col] + marker + current[col:]
310         lines[-1] = current.rstrip() + u'             # <<<<<<<<<<<<<<\n'
311         lines += contents[line:line+2]
312         return u'"%s":%d:%d\n%s\n' % (
313             source_desc.get_escaped_description(), line, col, u''.join(lines))
314
315 class CompilerDirectivesNode(Node):
316     """
317     Sets compiler directives for the children nodes
318     """
319     #  directives     {string:value}  A dictionary holding the right value for
320     #                                 *all* possible directives.
321     #  body           Node
322     child_attrs = ["body"]
323
324     def analyse_declarations(self, env):
325         old = env.directives
326         env.directives = self.directives
327         self.body.analyse_declarations(env)
328         env.directives = old
329
330     def analyse_expressions(self, env):
331         old = env.directives
332         env.directives = self.directives
333         self.body = self.body.analyse_expressions(env)
334         env.directives = old
335         return self
336
337     def generate_function_definitions(self, env, code):
338         env_old = env.directives
339         code_old = code.globalstate.directives
340         code.globalstate.directives = self.directives
341         self.body.generate_function_definitions(env, code)
342         env.directives = env_old
343         code.globalstate.directives = code_old
344
345     def generate_execution_code(self, code):
346         old = code.globalstate.directives
347         code.globalstate.directives = self.directives
348         self.body.generate_execution_code(code)
349         code.globalstate.directives = old
350
351     def annotate(self, code):
352         old = code.globalstate.directives
353         code.globalstate.directives = self.directives
354         self.body.annotate(code)
355         code.globalstate.directives = old
356
357 class BlockNode(object):
358     #  Mixin class for nodes representing a declaration block.
359
360     def generate_cached_builtins_decls(self, env, code):
361         entries = env.global_scope().undeclared_cached_builtins
362         for entry in entries:
363             code.globalstate.add_cached_builtin_decl(entry)
364         del entries[:]
365
366     def generate_lambda_definitions(self, env, code):
367         for node in env.lambda_defs:
368             node.generate_function_definitions(env, code)
369
370 class StatListNode(Node):
371     # stats     a list of StatNode
372
373     child_attrs = ["stats"]
374
375     def create_analysed(pos, env, *args, **kw):
376         node = StatListNode(pos, *args, **kw)
377         return node # No node-specific analysis necesarry
378     create_analysed = staticmethod(create_analysed)
379
380     def analyse_declarations(self, env):
381         #print "StatListNode.analyse_declarations" ###
382         for stat in self.stats:
383             stat.analyse_declarations(env)
384
385     def analyse_expressions(self, env):
386         #print "StatListNode.analyse_expressions" ###
387         self.stats = [ stat.analyse_expressions(env)
388                        for stat in self.stats ]
389         return self
390
391     def generate_function_definitions(self, env, code):
392         #print "StatListNode.generate_function_definitions" ###
393         for stat in self.stats:
394             stat.generate_function_definitions(env, code)
395
396     def generate_execution_code(self, code):
397         #print "StatListNode.generate_execution_code" ###
398         for stat in self.stats:
399             code.mark_pos(stat.pos)
400             stat.generate_execution_code(code)
401
402     def annotate(self, code):
403         for stat in self.stats:
404             stat.annotate(code)
405
406
407 class StatNode(Node):
408     #
409     #  Code generation for statements is split into the following subphases:
410     #
411     #  (1) generate_function_definitions
412     #        Emit C code for the definitions of any structs,
413     #        unions, enums and functions defined in the current
414     #        scope-block.
415     #
416     #  (2) generate_execution_code
417     #        Emit C code for executable statements.
418     #
419
420     def generate_function_definitions(self, env, code):
421         pass
422
423     def generate_execution_code(self, code):
424         raise InternalError("generate_execution_code not implemented for %s" % \
425             self.__class__.__name__)
426
427
428 class CDefExternNode(StatNode):
429     #  include_file   string or None
430     #  body           StatNode
431
432     child_attrs = ["body"]
433
434     def analyse_declarations(self, env):
435         if self.include_file:
436             env.add_include_file(self.include_file)
437         old_cinclude_flag = env.in_cinclude
438         env.in_cinclude = 1
439         self.body.analyse_declarations(env)
440         env.in_cinclude = old_cinclude_flag
441
442     def analyse_expressions(self, env):
443         return self
444
445     def generate_execution_code(self, code):
446         pass
447
448     def annotate(self, code):
449         self.body.annotate(code)
450
451
452 class CDeclaratorNode(Node):
453     # Part of a C declaration.
454     #
455     # Processing during analyse_declarations phase:
456     #
457     #   analyse
458     #      Returns (name, type) pair where name is the
459     #      CNameDeclaratorNode of the name being declared
460     #      and type is the type it is being declared as.
461     #
462     #  calling_convention  string   Calling convention of CFuncDeclaratorNode
463     #                               for which this is a base
464
465     child_attrs = []
466
467     calling_convention = ""
468
469     def analyse_templates(self):
470         # Only C++ functions have templates.
471         return None
472
473 class CNameDeclaratorNode(CDeclaratorNode):
474     #  name    string             The Cython name being declared
475     #  cname   string or None     C name, if specified
476     #  default ExprNode or None   the value assigned on declaration
477
478     child_attrs = ['default']
479
480     default = None
481
482     def analyse(self, base_type, env, nonempty = 0):
483         if nonempty and self.name == '':
484             # May have mistaken the name for the type.
485             if base_type.is_ptr or base_type.is_array or base_type.is_buffer:
486                 error(self.pos, "Missing argument name")
487             elif base_type.is_void:
488                 error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
489             else:
490                 self.name = base_type.declaration_code("", for_display=1, pyrex=1)
491                 base_type = py_object_type
492
493         if base_type.is_fused and env.fused_to_specific:
494             base_type = base_type.specialize(env.fused_to_specific)
495
496         self.type = base_type
497         return self, base_type
498
499 class CPtrDeclaratorNode(CDeclaratorNode):
500     # base     CDeclaratorNode
501
502     child_attrs = ["base"]
503
504     def analyse(self, base_type, env, nonempty = 0):
505         if base_type.is_pyobject:
506             error(self.pos,
507                 "Pointer base type cannot be a Python object")
508         ptr_type = PyrexTypes.c_ptr_type(base_type)
509         return self.base.analyse(ptr_type, env, nonempty = nonempty)
510
511 class CReferenceDeclaratorNode(CDeclaratorNode):
512     # base     CDeclaratorNode
513
514     child_attrs = ["base"]
515
516     def analyse(self, base_type, env, nonempty = 0):
517         if base_type.is_pyobject:
518             error(self.pos,
519                   "Reference base type cannot be a Python object")
520         ref_type = PyrexTypes.c_ref_type(base_type)
521         return self.base.analyse(ref_type, env, nonempty = nonempty)
522
523 class CArrayDeclaratorNode(CDeclaratorNode):
524     # base        CDeclaratorNode
525     # dimension   ExprNode
526
527     child_attrs = ["base", "dimension"]
528
529     def analyse(self, base_type, env, nonempty = 0):
530         if base_type.is_cpp_class or base_type.is_cfunction:
531             from ExprNodes import TupleNode
532             if isinstance(self.dimension, TupleNode):
533                 args = self.dimension.args
534             else:
535                 args = self.dimension,
536             values = [v.analyse_as_type(env) for v in args]
537             if None in values:
538                 ix = values.index(None)
539                 error(args[ix].pos, "Template parameter not a type")
540                 base_type = error_type
541             else:
542                 base_type = base_type.specialize_here(self.pos, values)
543             return self.base.analyse(base_type, env, nonempty = nonempty)
544         if self.dimension:
545             self.dimension = self.dimension.analyse_const_expression(env)
546             if not self.dimension.type.is_int:
547                 error(self.dimension.pos, "Array dimension not integer")
548             size = self.dimension.get_constant_c_result_code()
549             if size is not None:
550                 try:
551                     size = int(size)
552                 except ValueError:
553                     # runtime constant?
554                     pass
555         else:
556             size = None
557         if not base_type.is_complete():
558             error(self.pos,
559                 "Array element type '%s' is incomplete" % base_type)
560         if base_type.is_pyobject:
561             error(self.pos,
562                 "Array element cannot be a Python object")
563         if base_type.is_cfunction:
564             error(self.pos,
565                 "Array element cannot be a function")
566         array_type = PyrexTypes.c_array_type(base_type, size)
567         return self.base.analyse(array_type, env, nonempty = nonempty)
568
569
570 class CFuncDeclaratorNode(CDeclaratorNode):
571     # base             CDeclaratorNode
572     # args             [CArgDeclNode]
573     # templates        [TemplatePlaceholderType]
574     # has_varargs      boolean
575     # exception_value  ConstNode
576     # exception_check  boolean    True if PyErr_Occurred check needed
577     # nogil            boolean    Can be called without gil
578     # with_gil         boolean    Acquire gil around function body
579     # is_const_method  boolean    Whether this is a const method
580
581     child_attrs = ["base", "args", "exception_value"]
582
583     overridable = 0
584     optional_arg_count = 0
585     is_const_method = 0
586     templates = None
587
588     def analyse_templates(self):
589         if isinstance(self.base, CArrayDeclaratorNode):
590             from ExprNodes import TupleNode, NameNode
591             template_node = self.base.dimension
592             if isinstance(template_node, TupleNode):
593                 template_nodes = template_node.args
594             elif isinstance(template_node, NameNode):
595                 template_nodes = [template_node]
596             else:
597                 error(template_node.pos, "Template arguments must be a list of names")
598                 return None
599             self.templates = []
600             for template in template_nodes:
601                 if isinstance(template, NameNode):
602                     self.templates.append(PyrexTypes.TemplatePlaceholderType(template.name))
603                 else:
604                     error(template.pos, "Template arguments must be a list of names")
605             self.base = self.base.base
606             return self.templates
607         else:
608             return None
609
610     def analyse(self, return_type, env, nonempty = 0, directive_locals = {}):
611         if nonempty:
612             nonempty -= 1
613         func_type_args = []
614         for i, arg_node in enumerate(self.args):
615             name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
616                                                      is_self_arg = (i == 0 and env.is_c_class_scope))
617             name = name_declarator.name
618             if name in directive_locals:
619                 type_node = directive_locals[name]
620                 other_type = type_node.analyse_as_type(env)
621                 if other_type is None:
622                     error(type_node.pos, "Not a type")
623                 elif (type is not PyrexTypes.py_object_type
624                       and not type.same_as(other_type)):
625                     error(self.base.pos, "Signature does not agree with previous declaration")
626                     error(type_node.pos, "Previous declaration here")
627                 else:
628                     type = other_type
629             if name_declarator.cname:
630                 error(self.pos,
631                     "Function argument cannot have C name specification")
632             if i==0 and env.is_c_class_scope and type.is_unspecified:
633                 # fix the type of self
634                 type = env.parent_type
635             # Turn *[] argument into **
636             if type.is_array:
637                 type = PyrexTypes.c_ptr_type(type.base_type)
638             # Catch attempted C-style func(void) decl
639             if type.is_void:
640                 error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
641             func_type_args.append(
642                 PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
643             if arg_node.default:
644                 self.optional_arg_count += 1
645             elif self.optional_arg_count:
646                 error(self.pos, "Non-default argument follows default argument")
647
648         exc_val = None
649         exc_check = 0
650         if self.exception_check == '+':
651             env.add_include_file('ios')         # for std::ios_base::failure
652             env.add_include_file('new')         # for std::bad_alloc
653             env.add_include_file('stdexcept')
654             env.add_include_file('typeinfo')    # for std::bad_cast
655         if (return_type.is_pyobject
656                 and (self.exception_value or self.exception_check)
657                 and self.exception_check != '+'):
658             error(self.pos,
659                 "Exception clause not allowed for function returning Python object")
660         else:
661             if self.exception_value:
662                 self.exception_value = self.exception_value.analyse_const_expression(env)
663                 if self.exception_check == '+':
664                     exc_val_type = self.exception_value.type
665                     if (not exc_val_type.is_error
666                             and not exc_val_type.is_pyobject
667                             and not (exc_val_type.is_cfunction
668                                      and not exc_val_type.return_type.is_pyobject
669                                      and not exc_val_type.args)):
670                         error(self.exception_value.pos,
671                               "Exception value must be a Python exception or cdef function with no arguments.")
672                     exc_val = self.exception_value
673                 else:
674                     self.exception_value = self.exception_value.coerce_to(
675                         return_type, env).analyse_const_expression(env)
676                     exc_val = self.exception_value.get_constant_c_result_code()
677                     if exc_val is None:
678                         raise InternalError(
679                             "get_constant_c_result_code not implemented for %s" %
680                             self.exception_value.__class__.__name__)
681                     if not return_type.assignable_from(self.exception_value.type):
682                         error(self.exception_value.pos,
683                               "Exception value incompatible with function return type")
684             exc_check = self.exception_check
685         if return_type.is_cfunction:
686             error(self.pos,
687                 "Function cannot return a function")
688         func_type = PyrexTypes.CFuncType(
689             return_type, func_type_args, self.has_varargs,
690             optional_arg_count = self.optional_arg_count,
691             exception_value = exc_val, exception_check = exc_check,
692             calling_convention = self.base.calling_convention,
693             nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable,
694             is_const_method = self.is_const_method,
695             templates = self.templates)
696
697         if self.optional_arg_count:
698             if func_type.is_fused:
699                 # This is a bit of a hack... When we need to create specialized CFuncTypes
700                 # on the fly because the cdef is defined in a pxd, we need to declare the specialized optional arg
701                 # struct
702                 def declare_opt_arg_struct(func_type, fused_cname):
703                     self.declare_optional_arg_struct(func_type, env, fused_cname)
704
705                 func_type.declare_opt_arg_struct = declare_opt_arg_struct
706             else:
707                 self.declare_optional_arg_struct(func_type, env)
708
709         callspec = env.directives['callspec']
710         if callspec:
711             current = func_type.calling_convention
712             if current and current != callspec:
713                 error(self.pos, "cannot have both '%s' and '%s' "
714                       "calling conventions" % (current, callspec))
715             func_type.calling_convention = callspec
716         return self.base.analyse(func_type, env)
717
718     def declare_optional_arg_struct(self, func_type, env, fused_cname=None):
719         """
720         Declares the optional argument struct (the struct used to hold the
721         values for optional arguments). For fused cdef functions, this is
722         deferred as analyse_declarations is called only once (on the fused
723         cdef function).
724         """
725         scope = StructOrUnionScope()
726         arg_count_member = '%sn' % Naming.pyrex_prefix
727         scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)
728
729         for arg in func_type.args[len(func_type.args)-self.optional_arg_count:]:
730             scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
731
732         struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
733
734         if fused_cname is not None:
735             struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname)
736
737         op_args_struct = env.global_scope().declare_struct_or_union(
738                 name = struct_cname,
739                 kind = 'struct',
740                 scope = scope,
741                 typedef_flag = 0,
742                 pos = self.pos,
743                 cname = struct_cname)
744
745         op_args_struct.defined_in_pxd = 1
746         op_args_struct.used = 1
747
748         func_type.op_arg_struct = PyrexTypes.c_ptr_type(op_args_struct.type)
749
750
751 class CConstDeclaratorNode(CDeclaratorNode):
752     # base     CDeclaratorNode
753
754     child_attrs = ["base"]
755
756     def analyse(self, base_type, env, nonempty = 0):
757         if base_type.is_pyobject:
758             error(self.pos,
759                   "Const base type cannot be a Python object")
760         const = PyrexTypes.c_const_type(base_type)
761         return self.base.analyse(const, env, nonempty = nonempty)
762
763
764 class CArgDeclNode(Node):
765     # Item in a function declaration argument list.
766     #
767     # base_type      CBaseTypeNode
768     # declarator     CDeclaratorNode
769     # not_none       boolean            Tagged with 'not None'
770     # or_none        boolean            Tagged with 'or None'
771     # accept_none    boolean            Resolved boolean for not_none/or_none
772     # default        ExprNode or None
773     # default_value  PyObjectConst      constant for default value
774     # annotation     ExprNode or None   Py3 function arg annotation
775     # is_self_arg    boolean            Is the "self" arg of an extension type method
776     # is_type_arg    boolean            Is the "class" arg of an extension type classmethod
777     # is_kw_only     boolean            Is a keyword-only argument
778     # is_dynamic     boolean            Non-literal arg stored inside CyFunction
779
780     child_attrs = ["base_type", "declarator", "default", "annotation"]
781
782     is_self_arg = 0
783     is_type_arg = 0
784     is_generic = 1
785     kw_only = 0
786     not_none = 0
787     or_none = 0
788     type = None
789     name_declarator = None
790     default_value = None
791     annotation = None
792     is_dynamic = 0
793
794     def analyse(self, env, nonempty = 0, is_self_arg = False):
795         if is_self_arg:
796             self.base_type.is_self_arg = self.is_self_arg = True
797         if self.type is None:
798             # The parser may misinterpret names as types. We fix that here.
799             if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
800                 if nonempty:
801                     if self.base_type.is_basic_c_type:
802                         # char, short, long called "int"
803                         type = self.base_type.analyse(env, could_be_name = True)
804                         arg_name = type.declaration_code("")
805                     else:
806                         arg_name = self.base_type.name
807                     self.declarator.name = EncodedString(arg_name)
808                     self.base_type.name = None
809                     self.base_type.is_basic_c_type = False
810                 could_be_name = True
811             else:
812                 could_be_name = False
813             self.base_type.is_arg = True
814             base_type = self.base_type.analyse(env, could_be_name = could_be_name)
815             if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
816                 self.declarator.name = self.base_type.arg_name
817             # The parser is unable to resolve the ambiguity of [] as part of the
818             # type (e.g. in buffers) or empty declarator (as with arrays).
819             # This is only arises for empty multi-dimensional arrays.
820             if (base_type.is_array
821                     and isinstance(self.base_type, TemplatedTypeNode)
822                     and isinstance(self.declarator, CArrayDeclaratorNode)):
823                 declarator = self.declarator
824                 while isinstance(declarator.base, CArrayDeclaratorNode):
825                     declarator = declarator.base
826                 declarator.base = self.base_type.array_declarator
827                 base_type = base_type.base_type
828             return self.declarator.analyse(base_type, env, nonempty = nonempty)
829         else:
830             return self.name_declarator, self.type
831
832     def calculate_default_value_code(self, code):
833         if self.default_value is None:
834             if self.default:
835                 if self.default.is_literal:
836                     # will not output any code, just assign the result_code
837                     self.default.generate_evaluation_code(code)
838                     return self.type.cast_code(self.default.result())
839                 self.default_value = code.get_argument_default_const(self.type)
840         return self.default_value
841
842     def annotate(self, code):
843         if self.default:
844             self.default.annotate(code)
845
846     def generate_assignment_code(self, code, target=None):
847         default = self.default
848         if default is None or default.is_literal:
849             return
850         if target is None:
851             target = self.calculate_default_value_code(code)
852         default.generate_evaluation_code(code)
853         default.make_owned_reference(code)
854         result = default.result_as(self.type)
855         code.putln("%s = %s;" % (target, result))
856         if self.type.is_pyobject:
857             code.put_giveref(default.result())
858         default.generate_post_assignment_code(code)
859         default.free_temps(code)
860
861
862 class CBaseTypeNode(Node):
863     # Abstract base class for C base type nodes.
864     #
865     # Processing during analyse_declarations phase:
866     #
867     #   analyse
868     #     Returns the type.
869
870     pass
871
872     def analyse_as_type(self, env):
873         return self.analyse(env)
874
875 class CAnalysedBaseTypeNode(Node):
876     # type            type
877
878     child_attrs = []
879
880     def analyse(self, env, could_be_name = False):
881         return self.type
882
883 class CSimpleBaseTypeNode(CBaseTypeNode):
884     # name             string
885     # module_path      [string]     Qualifying name components
886     # is_basic_c_type  boolean
887     # signed           boolean
888     # longness         integer
889     # complex          boolean
890     # is_self_arg      boolean      Is self argument of C method
891     # ##is_type_arg      boolean      Is type argument of class method
892
893     child_attrs = []
894     arg_name = None   # in case the argument name was interpreted as a type
895     module_path = []
896     is_basic_c_type = False
897     complex = False
898
899     def analyse(self, env, could_be_name = False):
900         # Return type descriptor.
901         #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
902         type = None
903         if self.is_basic_c_type:
904             type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
905             if not type:
906                 error(self.pos, "Unrecognised type modifier combination")
907         elif self.name == "object" and not self.module_path:
908             type = py_object_type
909         elif self.name is None:
910             if self.is_self_arg and env.is_c_class_scope:
911                 #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
912                 type = env.parent_type
913             ## elif self.is_type_arg and env.is_c_class_scope:
914             ##     type = Builtin.type_type
915             else:
916                 type = py_object_type
917         else:
918             if self.module_path:
919                 # Maybe it's a nested C++ class.
920                 scope = env
921                 for item in self.module_path:
922                     entry = scope.lookup(item)
923                     if entry is not None and entry.is_cpp_class:
924                         scope = entry.type.scope
925                     else:
926                         scope = None
927                         break
928
929                 if scope is None:
930                     # Maybe it's a cimport.
931                     scope = env.find_imported_module(self.module_path, self.pos)
932                     if scope:
933                         scope.fused_to_specific = env.fused_to_specific
934             else:
935                 scope = env
936
937             if scope:
938                 if scope.is_c_class_scope:
939                     scope = scope.global_scope()
940
941                 type = scope.lookup_type(self.name)
942                 if type is not None:
943                     pass
944                 elif could_be_name:
945                     if self.is_self_arg and env.is_c_class_scope:
946                         type = env.parent_type
947                     ## elif self.is_type_arg and env.is_c_class_scope:
948                     ##     type = Builtin.type_type
949                     else:
950                         type = py_object_type
951                     self.arg_name = EncodedString(self.name)
952                 else:
953                     if self.templates:
954                         if not self.name in self.templates:
955                             error(self.pos, "'%s' is not a type identifier" % self.name)
956                         type = PyrexTypes.TemplatePlaceholderType(self.name)
957                     else:
958                         error(self.pos, "'%s' is not a type identifier" % self.name)
959         if self.complex:
960             if not type.is_numeric or type.is_complex:
961                 error(self.pos, "can only complexify c numeric types")
962             type = PyrexTypes.CComplexType(type)
963             type.create_declaration_utility_code(env)
964         elif type is Builtin.complex_type:
965             # Special case: optimise builtin complex type into C's
966             # double complex.  The parser cannot do this (as for the
967             # normal scalar types) as the user may have redeclared the
968             # 'complex' type.  Testing for the exact type here works.
969             type = PyrexTypes.c_double_complex_type
970             type.create_declaration_utility_code(env)
971             self.complex = True
972         if type:
973             return type
974         else:
975             return PyrexTypes.error_type
976
977 class MemoryViewSliceTypeNode(CBaseTypeNode):
978
979     name = 'memoryview'
980     child_attrs = ['base_type_node', 'axes']
981
982     def analyse(self, env, could_be_name = False):
983
984         base_type = self.base_type_node.analyse(env)
985         if base_type.is_error: return base_type
986
987         import MemoryView
988
989         try:
990             axes_specs = MemoryView.get_axes_specs(env, self.axes)
991         except CompileError, e:
992             error(e.position, e.message_only)
993             self.type = PyrexTypes.ErrorType()
994             return self.type
995
996         if not MemoryView.validate_axes(self.pos, axes_specs):
997             self.type = error_type
998         else:
999             MemoryView.validate_memslice_dtype(self.pos, base_type)
1000             self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs)
1001             self.use_memview_utilities(env)
1002
1003         return self.type
1004
1005     def use_memview_utilities(self, env):
1006         import MemoryView
1007         env.use_utility_code(MemoryView.view_utility_code)
1008
1009
1010 class CNestedBaseTypeNode(CBaseTypeNode):
1011     # For C++ classes that live inside other C++ classes.
1012
1013     # name             string
1014     # base_type        CBaseTypeNode
1015
1016     child_attrs = ['base_type']
1017
1018     def analyse(self, env, could_be_name = None):
1019         base_type = self.base_type.analyse(env)
1020         if base_type is PyrexTypes.error_type:
1021             return PyrexTypes.error_type
1022         if not base_type.is_cpp_class:
1023             error(self.pos, "'%s' is not a valid type scope" % base_type)
1024             return PyrexTypes.error_type
1025         type_entry = base_type.scope.lookup_here(self.name)
1026         if not type_entry or not type_entry.is_type:
1027             error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name))
1028             return PyrexTypes.error_type
1029         return type_entry.type
1030
1031
1032 class TemplatedTypeNode(CBaseTypeNode):
1033     #  After parsing:
1034     #  positional_args  [ExprNode]        List of positional arguments
1035     #  keyword_args     DictNode          Keyword arguments
1036     #  base_type_node   CBaseTypeNode
1037
1038     #  After analysis:
1039     #  type             PyrexTypes.BufferType or PyrexTypes.CppClassType  ...containing the right options
1040
1041     child_attrs = ["base_type_node", "positional_args",
1042                    "keyword_args", "dtype_node"]
1043
1044     dtype_node = None
1045
1046     name = None
1047
1048     def analyse(self, env, could_be_name = False, base_type = None):
1049         if base_type is None:
1050             base_type = self.base_type_node.analyse(env)
1051         if base_type.is_error: return base_type
1052
1053         if base_type.is_cpp_class:
1054             # Templated class
1055             if self.keyword_args and self.keyword_args.key_value_pairs:
1056                 error(self.pos, "c++ templates cannot take keyword arguments")
1057                 self.type = PyrexTypes.error_type
1058             else:
1059                 template_types = []
1060                 for template_node in self.positional_args:
1061                     type = template_node.analyse_as_type(env)
1062                     if type is None:
1063                         error(template_node.pos, "unknown type in template argument")
1064                         return error_type
1065                     template_types.append(type)
1066                 self.type = base_type.specialize_here(self.pos, template_types)
1067
1068         elif base_type.is_pyobject:
1069             # Buffer
1070             import Buffer
1071
1072             options = Buffer.analyse_buffer_options(
1073                 self.pos,
1074                 env,
1075                 self.positional_args,
1076                 self.keyword_args,
1077                 base_type.buffer_defaults)
1078
1079             if sys.version_info[0] < 3:
1080                 # Py 2.x enforces byte strings as keyword arguments ...
1081                 options = dict([ (name.encode('ASCII'), value)
1082                                  for name, value in options.items() ])
1083
1084             self.type = PyrexTypes.BufferType(base_type, **options)
1085
1086         else:
1087             # Array
1088             empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
1089             if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
1090                 error(self.pos, "invalid array declaration")
1091                 self.type = PyrexTypes.error_type
1092             else:
1093                 # It would be nice to merge this class with CArrayDeclaratorNode,
1094                 # but arrays are part of the declaration, not the type...
1095                 if not self.positional_args:
1096                     dimension = None
1097                 else:
1098                     dimension = self.positional_args[0]
1099                 self.array_declarator = CArrayDeclaratorNode(self.pos,
1100                     base = empty_declarator,
1101                     dimension = dimension)
1102                 self.type = self.array_declarator.analyse(base_type, env)[1]
1103
1104         if self.type.is_fused and env.fused_to_specific:
1105             self.type = self.type.specialize(env.fused_to_specific)
1106
1107         return self.type
1108
1109 class CComplexBaseTypeNode(CBaseTypeNode):
1110     # base_type   CBaseTypeNode
1111     # declarator  CDeclaratorNode
1112
1113     child_attrs = ["base_type", "declarator"]
1114
1115     def analyse(self, env, could_be_name = False):
1116         base = self.base_type.analyse(env, could_be_name)
1117         _, type = self.declarator.analyse(base, env)
1118         return type
1119
1120
1121 class FusedTypeNode(CBaseTypeNode):
1122     """
1123     Represents a fused type in a ctypedef statement:
1124
1125         ctypedef cython.fused_type(int, long, long long) integral
1126
1127     name            str                     name of this fused type
1128     types           [CSimpleBaseTypeNode]   is the list of types to be fused
1129     """
1130
1131     child_attrs = []
1132
1133     def analyse_declarations(self, env):
1134         type = self.analyse(env)
1135         entry = env.declare_typedef(self.name, type, self.pos)
1136
1137         # Omit the typedef declaration that self.declarator would produce
1138         entry.in_cinclude = True
1139
1140     def analyse(self, env):
1141         types = []
1142         for type_node in self.types:
1143             type = type_node.analyse_as_type(env)
1144
1145             if not type:
1146                 error(type_node.pos, "Not a type")
1147                 continue
1148
1149             if type in types:
1150                 error(type_node.pos, "Type specified multiple times")
1151             elif type.is_fused:
1152                 error(type_node.pos, "Cannot fuse a fused type")
1153             else:
1154                 types.append(type)
1155
1156         # if len(self.types) == 1:
1157         #     return types[0]
1158
1159         return PyrexTypes.FusedType(types, name=self.name)
1160
1161
1162 class CConstTypeNode(CBaseTypeNode):
1163     # base_type     CBaseTypeNode
1164
1165     child_attrs = ["base_type"]
1166
1167     def analyse(self, env, could_be_name = False):
1168         base = self.base_type.analyse(env, could_be_name)
1169         if base.is_pyobject:
1170             error(self.pos,
1171                   "Const base type cannot be a Python object")
1172         return PyrexTypes.c_const_type(base)
1173
1174
1175 class CVarDefNode(StatNode):
1176     #  C variable definition or forward/extern function declaration.
1177     #
1178     #  visibility    'private' or 'public' or 'extern'
1179     #  base_type     CBaseTypeNode
1180     #  declarators   [CDeclaratorNode]
1181     #  in_pxd        boolean
1182     #  api           boolean
1183     #  overridable   boolean        whether it is a cpdef
1184     #  modifiers     ['inline']
1185
1186     #  decorators    [cython.locals(...)] or None
1187     #  directive_locals { string : NameNode } locals defined by cython.locals(...)
1188
1189     child_attrs = ["base_type", "declarators"]
1190
1191     decorators = None
1192     directive_locals = None
1193
1194     def analyse_declarations(self, env, dest_scope = None):
1195         if self.directive_locals is None:
1196             self.directive_locals = {}
1197         if not dest_scope:
1198             dest_scope = env
1199         self.dest_scope = dest_scope
1200
1201         if self.declarators:
1202             templates = self.declarators[0].analyse_templates()
1203         else:
1204             templates = None
1205         if templates is not None:
1206             if self.visibility != 'extern':
1207                 error(self.pos, "Only extern functions allowed")
1208             if len(self.declarators) > 1:
1209                 error(self.declarators[1].pos, "Can't multiply declare template types")
1210             env = TemplateScope('func_template', env)
1211             env.directives = env.outer_scope.directives
1212             for template_param in templates:
1213                 env.declare_type(template_param.name, template_param, self.pos)
1214
1215         base_type = self.base_type.analyse(env)
1216
1217         if base_type.is_fused and not self.in_pxd and (env.is_c_class_scope or
1218                                                        env.is_module_scope):
1219             error(self.pos, "Fused types not allowed here")
1220             return error_type
1221
1222         self.entry = None
1223         visibility = self.visibility
1224
1225         for declarator in self.declarators:
1226
1227             if (len(self.declarators) > 1
1228                 and not isinstance(declarator, CNameDeclaratorNode)
1229                 and env.directives['warn.multiple_declarators']):
1230                 warning(declarator.pos,
1231                     "Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). " +
1232                     "Each pointer declaration should be on its own line.", 1)
1233
1234             if isinstance(declarator, CFuncDeclaratorNode):
1235                 name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
1236             else:
1237                 name_declarator, type = declarator.analyse(base_type, env)
1238             if not type.is_complete():
1239                 if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice):
1240                     error(declarator.pos,
1241                         "Variable type '%s' is incomplete" % type)
1242             if self.visibility == 'extern' and type.is_pyobject:
1243                 error(declarator.pos,
1244                     "Python object cannot be declared extern")
1245             name = name_declarator.name
1246             cname = name_declarator.cname
1247             if name == '':
1248                 error(declarator.pos, "Missing name in declaration.")
1249                 return
1250             if type.is_cfunction:
1251                 self.entry = dest_scope.declare_cfunction(name, type, declarator.pos,
1252                     cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
1253                     api = self.api, modifiers = self.modifiers)
1254                 if self.entry is not None:
1255                     self.entry.is_overridable = self.overridable
1256                     self.entry.directive_locals = copy.copy(self.directive_locals)
1257             else:
1258                 if self.directive_locals:
1259                     error(self.pos, "Decorators can only be followed by functions")
1260                 self.entry = dest_scope.declare_var(name, type, declarator.pos,
1261                             cname=cname, visibility=visibility, in_pxd=self.in_pxd,
1262                             api=self.api, is_cdef=1)
1263                 if Options.docstrings:
1264                     self.entry.doc = embed_position(self.pos, self.doc)
1265
1266
1267 class CStructOrUnionDefNode(StatNode):
1268     #  name          string
1269     #  cname         string or None
1270     #  kind          "struct" or "union"
1271     #  typedef_flag  boolean
1272     #  visibility    "public" or "private"
1273     #  api           boolean
1274     #  in_pxd        boolean
1275     #  attributes    [CVarDefNode] or None
1276     #  entry         Entry
1277     #  packed        boolean
1278
1279     child_attrs = ["attributes"]
1280
1281     def declare(self, env, scope=None):
1282         if self.visibility == 'extern' and self.packed and not scope:
1283             error(self.pos, "Cannot declare extern struct as 'packed'")
1284         self.entry = env.declare_struct_or_union(
1285             self.name, self.kind, scope, self.typedef_flag, self.pos,
1286             self.cname, visibility = self.visibility, api = self.api,
1287             packed = self.packed)
1288
1289     def analyse_declarations(self, env):
1290         scope = None
1291         if self.attributes is not None:
1292             scope = StructOrUnionScope(self.name)
1293         self.declare(env, scope)
1294         if self.attributes is not None:
1295             if self.in_pxd and not env.in_cinclude:
1296                 self.entry.defined_in_pxd = 1
1297             for attr in self.attributes:
1298                 attr.analyse_declarations(env, scope)
1299             if self.visibility != 'extern':
1300                 for attr in scope.var_entries:
1301                     type = attr.type
1302                     while type.is_array:
1303                         type = type.base_type
1304                     if type == self.entry.type:
1305                         error(attr.pos, "Struct cannot contain itself as a member.")
1306
1307     def analyse_expressions(self, env):
1308         return self
1309
1310     def generate_execution_code(self, code):
1311         pass
1312
1313
1314 class CppClassNode(CStructOrUnionDefNode, BlockNode):
1315
1316     #  name          string
1317     #  cname         string or None
1318     #  visibility    "extern"
1319     #  in_pxd        boolean
1320     #  attributes    [CVarDefNode] or None
1321     #  entry         Entry
1322     #  base_classes  [CBaseTypeNode]
1323     #  templates     [string] or None
1324
1325     def declare(self, env):
1326         if self.templates is None:
1327             template_types = None
1328         else:
1329             template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
1330         self.entry = env.declare_cpp_class(
1331             self.name, None, self.pos,
1332             self.cname, base_classes = [], visibility = self.visibility, templates = template_types)
1333
1334     def analyse_declarations(self, env):
1335         scope = None
1336         if self.attributes is not None:
1337             scope = CppClassScope(self.name, env, templates = self.templates)
1338         def base_ok(base_class):
1339             if base_class.is_cpp_class or base_class.is_struct:
1340                 return True
1341             else:
1342                 error(self.pos, "Base class '%s' not a struct or class." % base_class)
1343         base_class_types = filter(base_ok, [b.analyse(scope or env) for b in self.base_classes])
1344         if self.templates is None:
1345             template_types = None
1346         else:
1347             template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
1348         self.entry = env.declare_cpp_class(
1349             self.name, scope, self.pos,
1350             self.cname, base_class_types, visibility = self.visibility, templates = template_types)
1351         if self.entry is None:
1352             return
1353         self.entry.is_cpp_class = 1
1354         if scope is not None:
1355             scope.type = self.entry.type
1356         defined_funcs = []
1357         if self.attributes is not None:
1358             if self.in_pxd and not env.in_cinclude:
1359                 self.entry.defined_in_pxd = 1
1360             for attr in self.attributes:
1361                 attr.analyse_declarations(scope)
1362                 if isinstance(attr, CFuncDefNode):
1363                     defined_funcs.append(attr)
1364                     if self.templates is not None:
1365                         attr.template_declaration = "template <typename %s>" % ", typename ".join(self.templates)
1366         self.body = StatListNode(self.pos, stats=defined_funcs)
1367         self.scope = scope
1368
1369     def analyse_expressions(self, env):
1370         self.body = self.body.analyse_expressions(self.entry.type.scope)
1371         return self
1372
1373     def generate_function_definitions(self, env, code):
1374         self.body.generate_function_definitions(self.entry.type.scope, code)
1375
1376     def generate_execution_code(self, code):
1377         self.body.generate_execution_code(code)
1378
1379     def annotate(self, code):
1380         self.body.annotate(code)
1381
1382
1383 class CEnumDefNode(StatNode):
1384     #  name           string or None
1385     #  cname          string or None
1386     #  items          [CEnumDefItemNode]
1387     #  typedef_flag   boolean
1388     #  visibility     "public" or "private"
1389     #  api            boolean
1390     #  in_pxd         boolean
1391     #  entry          Entry
1392
1393     child_attrs = ["items"]
1394
1395     def declare(self, env):
1396          self.entry = env.declare_enum(self.name, self.pos,
1397              cname = self.cname, typedef_flag = self.typedef_flag,
1398              visibility = self.visibility, api = self.api)
1399
1400     def analyse_declarations(self, env):
1401         if self.items is not None:
1402             if self.in_pxd and not env.in_cinclude:
1403                 self.entry.defined_in_pxd = 1
1404             for item in self.items:
1405                 item.analyse_declarations(env, self.entry)
1406
1407     def analyse_expressions(self, env):
1408         return self
1409
1410     def generate_execution_code(self, code):
1411         if self.visibility == 'public' or self.api:
1412             temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
1413             for item in self.entry.enum_values:
1414                 code.putln("%s = PyInt_FromLong(%s); %s" % (
1415                         temp,
1416                         item.cname,
1417                         code.error_goto_if_null(temp, item.pos)))
1418                 code.put_gotref(temp)
1419                 code.putln('if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % (
1420                         Naming.moddict_cname,
1421                         item.name,
1422                         temp,
1423                         code.error_goto(item.pos)))
1424                 code.put_decref_clear(temp, PyrexTypes.py_object_type)
1425             code.funcstate.release_temp(temp)
1426
1427
1428 class CEnumDefItemNode(StatNode):
1429     #  name     string
1430     #  cname    string or None
1431     #  value    ExprNode or None
1432
1433     child_attrs = ["value"]
1434
1435     def analyse_declarations(self, env, enum_entry):
1436         if self.value:
1437             self.value = self.value.analyse_const_expression(env)
1438             if not self.value.type.is_int:
1439                 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
1440                 self.value = self.value.analyse_const_expression(env)
1441         entry = env.declare_const(self.name, enum_entry.type,
1442             self.value, self.pos, cname = self.cname,
1443             visibility = enum_entry.visibility, api = enum_entry.api)
1444         enum_entry.enum_values.append(entry)
1445
1446
1447 class CTypeDefNode(StatNode):
1448     #  base_type    CBaseTypeNode
1449     #  declarator   CDeclaratorNode
1450     #  visibility   "public" or "private"
1451     #  api          boolean
1452     #  in_pxd       boolean
1453
1454     child_attrs = ["base_type", "declarator"]
1455
1456     def analyse_declarations(self, env):
1457         base = self.base_type.analyse(env)
1458         name_declarator, type = self.declarator.analyse(base, env)
1459         name = name_declarator.name
1460         cname = name_declarator.cname
1461
1462         entry = env.declare_typedef(name, type, self.pos,
1463             cname = cname, visibility = self.visibility, api = self.api)
1464
1465         if type.is_fused:
1466             entry.in_cinclude = True
1467
1468         if self.in_pxd and not env.in_cinclude:
1469             entry.defined_in_pxd = 1
1470
1471     def analyse_expressions(self, env):
1472         return self
1473
1474     def generate_execution_code(self, code):
1475         pass
1476
1477
1478 class FuncDefNode(StatNode, BlockNode):
1479     #  Base class for function definition nodes.
1480     #
1481     #  return_type     PyrexType
1482     #  #filename        string        C name of filename string const
1483     #  entry           Symtab.Entry
1484     #  needs_closure   boolean        Whether or not this function has inner functions/classes/yield
1485     #  needs_outer_scope boolean      Whether or not this function requires outer scope
1486     #  pymethdef_required boolean     Force Python method struct generation
1487     #  directive_locals { string : ExprNode } locals defined by cython.locals(...)
1488     #  directive_returns [ExprNode] type defined by cython.returns(...)
1489     # star_arg      PyArgDeclNode or None  * argument
1490     # starstar_arg  PyArgDeclNode or None  ** argument
1491
1492     #  has_fused_arguments  boolean
1493     #       Whether this cdef function has fused parameters. This is needed
1494     #       by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes
1495     #       with fused argument types with a FusedCFuncDefNode
1496
1497     py_func = None
1498     needs_closure = False
1499     needs_outer_scope = False
1500     pymethdef_required = False
1501     is_generator = False
1502     is_generator_body = False
1503     modifiers = []
1504     has_fused_arguments = False
1505     star_arg = None
1506     starstar_arg = None
1507     is_cyfunction = False
1508
1509     def analyse_default_values(self, env):
1510         default_seen = 0
1511         for arg in self.args:
1512             if arg.default:
1513                 default_seen = 1
1514                 if arg.is_generic:
1515                     arg.default = arg.default.analyse_types(env)
1516                     arg.default = arg.default.coerce_to(arg.type, env)
1517                 else:
1518                     error(arg.pos,
1519                         "This argument cannot have a default value")
1520                     arg.default = None
1521             elif arg.kw_only:
1522                 default_seen = 1
1523             elif default_seen:
1524                 error(arg.pos, "Non-default argument following default argument")
1525
1526     def align_argument_type(self, env, arg):
1527         directive_locals = self.directive_locals
1528         type = arg.type
1529         if arg.name in directive_locals:
1530             type_node = directive_locals[arg.name]
1531             other_type = type_node.analyse_as_type(env)
1532             if other_type is None:
1533                 error(type_node.pos, "Not a type")
1534             elif (type is not PyrexTypes.py_object_type
1535                     and not type.same_as(other_type)):
1536                 error(arg.base_type.pos, "Signature does not agree with previous declaration")
1537                 error(type_node.pos, "Previous declaration here")
1538             else:
1539                 arg.type = other_type
1540         return arg
1541
1542     def need_gil_acquisition(self, lenv):
1543         return 0
1544
1545     def create_local_scope(self, env):
1546         genv = env
1547         while genv.is_py_class_scope or genv.is_c_class_scope:
1548             genv = genv.outer_scope
1549         if self.needs_closure:
1550             lenv = ClosureScope(name=self.entry.name,
1551                                 outer_scope = genv,
1552                                 parent_scope = env,
1553                                 scope_name=self.entry.cname)
1554         else:
1555             lenv = LocalScope(name=self.entry.name,
1556                               outer_scope=genv,
1557                               parent_scope=env)
1558         lenv.return_type = self.return_type
1559         type = self.entry.type
1560         if type.is_cfunction:
1561             lenv.nogil = type.nogil and not type.with_gil
1562         self.local_scope = lenv
1563         lenv.directives = env.directives
1564         return lenv
1565
1566     def generate_function_body(self, env, code):
1567         self.body.generate_execution_code(code)
1568
1569     def generate_function_definitions(self, env, code):
1570         import Buffer
1571         if self.return_type.is_memoryviewslice:
1572             import MemoryView
1573
1574         lenv = self.local_scope
1575         if lenv.is_closure_scope and not lenv.is_passthrough:
1576             outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
1577                                             Naming.outer_scope_cname)
1578         else:
1579             outer_scope_cname = Naming.outer_scope_cname
1580         lenv.mangle_closure_cnames(outer_scope_cname)
1581         # Generate closure function definitions
1582         self.body.generate_function_definitions(lenv, code)
1583         # generate lambda function definitions
1584         self.generate_lambda_definitions(lenv, code)
1585
1586         is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
1587                              self.entry.scope.is_c_class_scope)
1588         is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and
1589                                  self.entry.scope.is_c_class_scope)
1590         is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot
1591         if is_buffer_slot:
1592             if 'cython_unused' not in self.modifiers:
1593                 self.modifiers = self.modifiers + ['cython_unused']
1594
1595         preprocessor_guard = self.get_preprocessor_guard()
1596
1597         profile = code.globalstate.directives['profile']
1598         linetrace = code.globalstate.directives['linetrace']
1599         if (linetrace or profile) and lenv.nogil:
1600             warning(self.pos, "Cannot profile nogil function.", 1)
1601             profile = linetrace = False
1602         if profile or linetrace:
1603             code.globalstate.use_utility_code(
1604                 UtilityCode.load_cached("Profile", "Profile.c"))
1605
1606         # Generate C code for header and body of function
1607         code.enter_cfunc_scope()
1608         code.return_from_error_cleanup_label = code.new_label()
1609
1610         # ----- Top-level constants used by this function
1611         code.mark_pos(self.pos)
1612         self.generate_cached_builtins_decls(lenv, code)
1613         # ----- Function header
1614         code.putln("")
1615
1616         if preprocessor_guard:
1617             code.putln(preprocessor_guard)
1618
1619         with_pymethdef = (self.needs_assignment_synthesis(env, code) or
1620                           self.pymethdef_required)
1621         if self.py_func:
1622             self.py_func.generate_function_header(code,
1623                 with_pymethdef = with_pymethdef,
1624                 proto_only=True)
1625         self.generate_function_header(code,
1626             with_pymethdef = with_pymethdef)
1627         # ----- Local variable declarations
1628         # Find function scope
1629         cenv = env
1630         while cenv.is_py_class_scope or cenv.is_c_class_scope:
1631             cenv = cenv.outer_scope
1632         if self.needs_closure:
1633             code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
1634             code.putln(";")
1635         elif self.needs_outer_scope:
1636             if lenv.is_passthrough:
1637                 code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
1638                 code.putln(";")
1639             code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
1640             code.putln(";")
1641         self.generate_argument_declarations(lenv, code)
1642
1643         for entry in lenv.var_entries:
1644             if not (entry.in_closure or entry.is_arg):
1645                 code.put_var_declaration(entry)
1646
1647         # Initialize the return variable __pyx_r
1648         init = ""
1649         if not self.return_type.is_void:
1650             if self.return_type.is_pyobject:
1651                 init = " = NULL"
1652             elif self.return_type.is_memoryviewslice:
1653                 init = ' = ' + MemoryView.memslice_entry_init
1654
1655             code.putln(
1656                 "%s%s;" %
1657                     (self.return_type.declaration_code(Naming.retval_cname),
1658                      init))
1659
1660         tempvardecl_code = code.insertion_point()
1661         self.generate_keyword_list(code)
1662
1663         if profile or linetrace:
1664             code.put_trace_declarations()
1665
1666         # ----- Extern library function declarations
1667         lenv.generate_library_function_declarations(code)
1668
1669         # ----- GIL acquisition
1670         acquire_gil = self.acquire_gil
1671
1672         # See if we need to acquire the GIL for variable declarations, or for
1673         # refnanny only
1674
1675         # Profiling or closures are not currently possible for cdef nogil
1676         # functions, but check them anyway
1677         have_object_args = (self.needs_closure or self.needs_outer_scope or
1678                             profile or linetrace)
1679         for arg in lenv.arg_entries:
1680             if arg.type.is_pyobject:
1681                 have_object_args = True
1682                 break
1683
1684         acquire_gil_for_var_decls_only = (
1685                 lenv.nogil and lenv.has_with_gil_block and
1686                 (have_object_args or lenv.buffer_entries))
1687
1688         acquire_gil_for_refnanny_only = (
1689                 lenv.nogil and lenv.has_with_gil_block and not
1690                 acquire_gil_for_var_decls_only)
1691
1692         use_refnanny = not lenv.nogil or lenv.has_with_gil_block
1693
1694         if acquire_gil or acquire_gil_for_var_decls_only:
1695             code.put_ensure_gil()
1696         elif lenv.nogil and lenv.has_with_gil_block:
1697             code.declare_gilstate()
1698
1699         # ----- set up refnanny
1700         if use_refnanny:
1701             tempvardecl_code.put_declare_refcount_context()
1702             code.put_setup_refcount_context(
1703                 self.entry.name, acquire_gil=acquire_gil_for_refnanny_only)
1704
1705         # ----- Automatic lead-ins for certain special functions
1706         if is_getbuffer_slot:
1707             self.getbuffer_init(code)
1708         # ----- Create closure scope object
1709         if self.needs_closure:
1710             tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
1711             slot_func_cname = TypeSlots.get_slot_function(lenv.scope_class.type.scope, tp_slot)
1712             if not slot_func_cname:
1713                 slot_func_cname = '%s->tp_new' % lenv.scope_class.type.typeptr_cname
1714             code.putln("%s = (%s)%s(%s, %s, NULL);" % (
1715                 Naming.cur_scope_cname,
1716                 lenv.scope_class.type.declaration_code(''),
1717                 slot_func_cname,
1718                 lenv.scope_class.type.typeptr_cname,
1719                 Naming.empty_tuple))
1720             code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname)
1721             if is_getbuffer_slot:
1722                 self.getbuffer_error_cleanup(code)
1723
1724             if use_refnanny:
1725                 code.put_finish_refcount_context()
1726                 if acquire_gil or acquire_gil_for_var_decls_only:
1727                     code.put_release_ensured_gil()
1728
1729             # FIXME: what if the error return value is a Python value?
1730             code.putln("return %s;" % self.error_value())
1731             code.putln("}")
1732             code.put_gotref(Naming.cur_scope_cname)
1733             # Note that it is unsafe to decref the scope at this point.
1734         if self.needs_outer_scope:
1735             if self.is_cyfunction:
1736                 code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % (
1737                     outer_scope_cname,
1738                     cenv.scope_class.type.declaration_code(''),
1739                     Naming.self_cname))
1740             else:
1741                 code.putln("%s = (%s) %s;" % (
1742                     outer_scope_cname,
1743                     cenv.scope_class.type.declaration_code(''),
1744                     Naming.self_cname))
1745             if lenv.is_passthrough:
1746                 code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname))
1747             elif self.needs_closure:
1748                 # inner closures own a reference to their outer parent
1749                 code.put_incref(outer_scope_cname, cenv.scope_class.type)
1750                 code.put_giveref(outer_scope_cname)
1751         # ----- Trace function call
1752         if profile or linetrace:
1753             # this looks a bit late, but if we don't get here due to a
1754             # fatal error before hand, it's not really worth tracing
1755             code.put_trace_call(self.entry.name, self.pos)
1756             code.funcstate.can_trace = True
1757         # ----- Fetch arguments
1758         self.generate_argument_parsing_code(env, code)
1759         # If an argument is assigned to in the body, we must
1760         # incref it to properly keep track of refcounts.
1761         is_cdef = isinstance(self, CFuncDefNode)
1762         for entry in lenv.arg_entries:
1763             if entry.type.is_pyobject:
1764                 if ((acquire_gil or len(entry.cf_assignments) > 1) and
1765                     not entry.in_closure):
1766                     code.put_var_incref(entry)
1767
1768             # Note: defaults are always incref-ed. For def functions, we
1769             #       we aquire arguments from object converstion, so we have
1770             #       new references. If we are a cdef function, we need to
1771             #       incref our arguments
1772             elif (is_cdef and entry.type.is_memoryviewslice and
1773                   len(entry.cf_assignments) > 1):
1774                 code.put_incref_memoryviewslice(entry.cname,
1775                                                 have_gil=not lenv.nogil)
1776         for entry in lenv.var_entries:
1777             if entry.is_arg and len(entry.cf_assignments) > 1:
1778                 code.put_var_incref(entry)
1779
1780         # ----- Initialise local buffer auxiliary variables
1781         for entry in lenv.var_entries + lenv.arg_entries:
1782             if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used:
1783                 Buffer.put_init_vars(entry, code)
1784
1785         # ----- Check and convert arguments
1786         self.generate_argument_type_tests(code)
1787         # ----- Acquire buffer arguments
1788         for entry in lenv.arg_entries:
1789             if entry.type.is_buffer:
1790                 Buffer.put_acquire_arg_buffer(entry, code, self.pos)
1791
1792         if acquire_gil_for_var_decls_only:
1793             code.put_release_ensured_gil()
1794
1795         # -------------------------
1796         # ----- Function body -----
1797         # -------------------------
1798         self.generate_function_body(env, code)
1799
1800         code.mark_pos(self.pos)
1801         code.putln("")
1802         code.putln("/* function exit code */")
1803
1804         # ----- Default return value
1805         if not self.body.is_terminator:
1806             if self.return_type.is_pyobject:
1807                 #if self.return_type.is_extension_type:
1808                 #    lhs = "(PyObject *)%s" % Naming.retval_cname
1809                 #else:
1810                 lhs = Naming.retval_cname
1811                 code.put_init_to_py_none(lhs, self.return_type)
1812             else:
1813                 val = self.return_type.default_value
1814                 if val:
1815                     code.putln("%s = %s;" % (Naming.retval_cname, val))
1816         # ----- Error cleanup
1817         if code.error_label in code.labels_used:
1818             if not self.body.is_terminator:
1819                 code.put_goto(code.return_label)
1820             code.put_label(code.error_label)
1821             for cname, type in code.funcstate.all_managed_temps():
1822                 code.put_xdecref(cname, type, have_gil=not lenv.nogil)
1823
1824             # Clean up buffers -- this calls a Python function
1825             # so need to save and restore error state
1826             buffers_present = len(lenv.buffer_entries) > 0
1827             memslice_entries = [e for e in lenv.entries.itervalues()
1828                                       if e.type.is_memoryviewslice]
1829             if buffers_present:
1830                 code.globalstate.use_utility_code(restore_exception_utility_code)
1831                 code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
1832                 code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
1833                 for entry in lenv.buffer_entries:
1834                     Buffer.put_release_buffer_code(code, entry)
1835                     #code.putln("%s = 0;" % entry.cname)
1836                 code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
1837
1838             if self.return_type.is_memoryviewslice:
1839                 MemoryView.put_init_entry(Naming.retval_cname, code)
1840                 err_val = Naming.retval_cname
1841             else:
1842                 err_val = self.error_value()
1843
1844             exc_check = self.caller_will_check_exceptions()
1845             if err_val is not None or exc_check:
1846                 # TODO: Fix exception tracing (though currently unused by cProfile).
1847                 # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
1848                 # code.put_trace_exception()
1849
1850                 if lenv.nogil and not lenv.has_with_gil_block:
1851                     code.putln("{")
1852                     code.put_ensure_gil()
1853
1854                 code.put_add_traceback(self.entry.qualified_name)
1855
1856                 if lenv.nogil and not lenv.has_with_gil_block:
1857                     code.put_release_ensured_gil()
1858                     code.putln("}")
1859             else:
1860                 warning(self.entry.pos,
1861                         "Unraisable exception in function '%s'." %
1862                         self.entry.qualified_name, 0)
1863                 code.put_unraisable(self.entry.qualified_name)
1864             default_retval = self.return_type.default_value
1865             if err_val is None and default_retval:
1866                 err_val = default_retval
1867             if err_val is not None:
1868                 code.putln("%s = %s;" % (Naming.retval_cname, err_val))
1869
1870             if is_getbuffer_slot:
1871                 self.getbuffer_error_cleanup(code)
1872
1873             # If we are using the non-error cleanup section we should
1874             # jump past it if we have an error. The if-test below determine
1875             # whether this section is used.
1876             if buffers_present or is_getbuffer_slot or self.return_type.is_memoryviewslice:
1877                 code.put_goto(code.return_from_error_cleanup_label)
1878
1879         # ----- Non-error return cleanup
1880         code.put_label(code.return_label)
1881         for entry in lenv.buffer_entries:
1882             if entry.used:
1883                 Buffer.put_release_buffer_code(code, entry)
1884         if is_getbuffer_slot:
1885             self.getbuffer_normal_cleanup(code)
1886
1887         if self.return_type.is_memoryviewslice:
1888             # See if our return value is uninitialized on non-error return
1889             # import MemoryView
1890             # MemoryView.err_if_nogil_initialized_check(self.pos, env)
1891             cond = code.unlikely(self.return_type.error_condition(
1892                                                     Naming.retval_cname))
1893             code.putln(
1894                 'if (%s) {' % cond)
1895             if env.nogil:
1896                 code.put_ensure_gil()
1897             code.putln(
1898                     'PyErr_SetString('
1899                         'PyExc_TypeError,'
1900                         '"Memoryview return value is not initialized");')
1901             if env.nogil:
1902                 code.put_release_ensured_gil()
1903             code.putln(
1904                 '}')
1905
1906         # ----- Return cleanup for both error and no-error return
1907         code.put_label(code.return_from_error_cleanup_label)
1908
1909         for entry in lenv.var_entries:
1910             if not entry.used or entry.in_closure:
1911                 continue
1912
1913             if entry.type.is_memoryviewslice:
1914                 code.put_xdecref_memoryviewslice(entry.cname,
1915                                                  have_gil=not lenv.nogil)
1916             elif entry.type.is_pyobject:
1917                 if not entry.is_arg or len(entry.cf_assignments) > 1:
1918                     code.put_var_decref(entry)
1919
1920         # Decref any increfed args
1921         for entry in lenv.arg_entries:
1922             if entry.type.is_pyobject:
1923                 if ((acquire_gil or len(entry.cf_assignments) > 1) and
1924                     not entry.in_closure):
1925                     code.put_var_decref(entry)
1926             elif (entry.type.is_memoryviewslice and
1927                   (not is_cdef or len(entry.cf_assignments) > 1)):
1928                 # decref slices of def functions and acquired slices from cdef
1929                 # functions, but not borrowed slices from cdef functions.
1930                 code.put_xdecref_memoryviewslice(entry.cname,
1931                                                  have_gil=not lenv.nogil)
1932         if self.needs_closure:
1933             code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
1934
1935         # ----- Return
1936         # This code is duplicated in ModuleNode.generate_module_init_func
1937         if not lenv.nogil:
1938             default_retval = self.return_type.default_value
1939             err_val = self.error_value()
1940             if err_val is None and default_retval:
1941                 err_val = default_retval  # FIXME: why is err_val not used?
1942             if self.return_type.is_pyobject:
1943                 code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
1944
1945         if self.entry.is_special and self.entry.name == "__hash__":
1946             # Returning -1 for __hash__ is supposed to signal an error
1947             # We do as Python instances and coerce -1 into -2.
1948             code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (
1949                     Naming.retval_cname, Naming.retval_cname))
1950
1951         if profile or linetrace:
1952             code.funcstate.can_trace = False
1953             if self.return_type.is_pyobject:
1954                 code.put_trace_return(Naming.retval_cname)
1955             else:
1956                 code.put_trace_return("Py_None")
1957
1958         if not lenv.nogil:
1959             # GIL holding function
1960             code.put_finish_refcount_context()
1961
1962         if acquire_gil or (lenv.nogil and lenv.has_with_gil_block):
1963             # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
1964             code.put_release_ensured_gil()
1965
1966         if not self.return_type.is_void:
1967             code.putln("return %s;" % Naming.retval_cname)
1968
1969         code.putln("}")
1970
1971         if preprocessor_guard:
1972             code.putln("#endif /*!(%s)*/" % preprocessor_guard)
1973
1974         # ----- Go back and insert temp variable declarations
1975         tempvardecl_code.put_temp_declarations(code.funcstate)
1976
1977         # ----- Python version
1978         code.exit_cfunc_scope()
1979         if self.py_func:
1980             self.py_func.generate_function_definitions(env, code)
1981         self.generate_wrapper_functions(code)
1982
1983     def declare_argument(self, env, arg):
1984         if arg.type.is_void:
1985             error(arg.pos, "Invalid use of 'void'")
1986         elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice):
1987             error(arg.pos,
1988                 "Argument type '%s' is incomplete" % arg.type)
1989         return env.declare_arg(arg.name, arg.type, arg.pos)
1990
1991     def generate_arg_type_test(self, arg, code):
1992         # Generate type test for one argument.
1993         if arg.type.typeobj_is_available():
1994             code.globalstate.use_utility_code(
1995                 UtilityCode.load_cached("ArgTypeTest", "FunctionArguments.c"))
1996             typeptr_cname = arg.type.typeptr_cname
1997             arg_code = "((PyObject *)%s)" % arg.entry.cname
1998             code.putln(
1999                 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
2000                     arg_code,
2001                     typeptr_cname,
2002                     arg.accept_none,
2003                     arg.name,
2004                     arg.type.is_builtin_type,
2005                     code.error_goto(arg.pos)))
2006         else:
2007             error(arg.pos, "Cannot test type of extern C class "
2008                 "without type object name specification")
2009
2010     def generate_arg_none_check(self, arg, code):
2011         # Generate None check for one argument.
2012         if arg.type.is_memoryviewslice:
2013             cname = "%s.memview" % arg.entry.cname
2014         else:
2015             cname = arg.entry.cname
2016
2017         code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % cname)
2018         code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%%.%ds' must not be None", "%s"); %s''' % (
2019             max(200, len(arg.name)), arg.name,
2020             code.error_goto(arg.pos)))
2021         code.putln('}')
2022
2023     def generate_wrapper_functions(self, code):
2024         pass
2025
2026     def generate_execution_code(self, code):
2027         # Evaluate and store argument default values
2028         for arg in self.args:
2029             if not arg.is_dynamic:
2030                 arg.generate_assignment_code(code)
2031
2032     #
2033     # Special code for the __getbuffer__ function
2034     #
2035     def getbuffer_init(self, code):
2036         info = self.local_scope.arg_entries[1].cname
2037         # Python 3.0 betas have a bug in memoryview which makes it call
2038         # getbuffer with a NULL parameter. For now we work around this;
2039         # the following block should be removed when this bug is fixed.
2040         code.putln("if (%s != NULL) {" % info)
2041         code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
2042         code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
2043         code.putln("}")
2044
2045     def getbuffer_error_cleanup(self, code):
2046         info = self.local_scope.arg_entries[1].cname
2047         code.putln("if (%s != NULL && %s->obj != NULL) {"
2048                    % (info, info))
2049         code.put_gotref("%s->obj" % info)
2050         code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;"
2051                    % (info, info))
2052         code.putln("}")
2053
2054     def getbuffer_normal_cleanup(self, code):
2055         info = self.local_scope.arg_entries[1].cname
2056         code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info))
2057         code.put_gotref("Py_None")
2058         code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
2059         code.putln("}")
2060
2061     def get_preprocessor_guard(self):
2062         if not self.entry.is_special:
2063             return None
2064         name = self.entry.name
2065         slot = TypeSlots.method_name_to_slot.get(name)
2066         if not slot:
2067             return None
2068         if name == '__long__' and not self.entry.scope.lookup_here('__int__'):
2069             return None
2070         if name in ("__getbuffer__", "__releasebuffer__") and self.entry.scope.is_c_class_scope:
2071             return None
2072         return slot.preprocessor_guard_code()
2073
2074
2075 class CFuncDefNode(FuncDefNode):
2076     #  C function definition.
2077     #
2078     #  modifiers     ['inline']
2079     #  visibility    'private' or 'public' or 'extern'
2080     #  base_type     CBaseTypeNode
2081     #  declarator    CDeclaratorNode
2082     #  cfunc_declarator  the CFuncDeclarator of this function
2083     #                    (this is also available through declarator or a
2084     #                     base thereof)
2085     #  body          StatListNode
2086     #  api           boolean
2087     #  decorators    [DecoratorNode]        list of decorators
2088     #
2089     #  with_gil      boolean    Acquire GIL around body
2090     #  type          CFuncType
2091     #  py_func       wrapper for calling from Python
2092     #  overridable   whether or not this is a cpdef function
2093     #  inline_in_pxd whether this is an inline function in a pxd file
2094     #  template_declaration  String or None   Used for c++ class methods
2095     #  is_const_method whether this is a const method
2096
2097     child_attrs = ["base_type", "declarator", "body", "py_func"]
2098
2099     inline_in_pxd = False
2100     decorators = None
2101     directive_locals = None
2102     directive_returns = None
2103     override = None
2104     template_declaration = None
2105     is_const_method = False
2106
2107     def unqualified_name(self):
2108         return self.entry.name
2109
2110     def analyse_declarations(self, env):
2111         if self.directive_locals is None:
2112             self.directive_locals = {}
2113         self.directive_locals.update(env.directives['locals'])
2114         if self.directive_returns is not None:
2115             base_type = self.directive_returns.analyse_as_type(env)
2116             if base_type is None:
2117                 error(self.directive_returns.pos, "Not a type")
2118                 base_type = PyrexTypes.error_type
2119         else:
2120             base_type = self.base_type.analyse(env)
2121         # The 2 here is because we need both function and argument names.
2122         if isinstance(self.declarator, CFuncDeclaratorNode):
2123             name_declarator, type = self.declarator.analyse(base_type, env,
2124                                                             nonempty = 2 * (self.body is not None),
2125                                                             directive_locals = self.directive_locals)
2126         else:
2127             name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
2128         if not type.is_cfunction:
2129             error(self.pos,
2130                 "Suite attached to non-function declaration")
2131         # Remember the actual type according to the function header
2132         # written here, because the type in the symbol table entry
2133         # may be different if we're overriding a C method inherited
2134         # from the base type of an extension type.
2135         self.type = type
2136         type.is_overridable = self.overridable
2137         declarator = self.declarator
2138         while not hasattr(declarator, 'args'):
2139             declarator = declarator.base
2140
2141         self.cfunc_declarator = declarator
2142         self.args = declarator.args
2143
2144         opt_arg_count = self.cfunc_declarator.optional_arg_count
2145         if (self.visibility == 'public' or self.api) and opt_arg_count:
2146             error(self.cfunc_declarator.pos,
2147                   "Function with optional arguments may not be declared "
2148                   "public or api")
2149
2150         if (type.exception_check == '+' and self.visibility != 'extern'):
2151             warning(self.cfunc_declarator.pos,
2152                     "Only extern functions can throw C++ exceptions.")
2153
2154         for formal_arg, type_arg in zip(self.args, type.args):
2155             self.align_argument_type(env, type_arg)
2156             formal_arg.type = type_arg.type
2157             formal_arg.name = type_arg.name
2158             formal_arg.cname = type_arg.cname
2159
2160             self._validate_type_visibility(type_arg.type, type_arg.pos, env)
2161
2162             if type_arg.type.is_fused:
2163                 self.has_fused_arguments = True
2164
2165             if type_arg.type.is_buffer and 'inline' in self.modifiers:
2166                 warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)
2167
2168             if type_arg.type.is_buffer:
2169                 if self.type.nogil:
2170                     error(formal_arg.pos,
2171                           "Buffer may not be acquired without the GIL. "
2172                           "Consider using memoryview slices instead.")
2173                 elif 'inline' in self.modifiers:
2174                     warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)
2175
2176         self._validate_type_visibility(type.return_type, self.pos, env)
2177
2178         name = name_declarator.name
2179         cname = name_declarator.cname
2180
2181         type.is_const_method = self.is_const_method
2182         self.entry = env.declare_cfunction(
2183             name, type, self.pos,
2184             cname = cname, visibility = self.visibility, api = self.api,
2185             defining = self.body is not None, modifiers = self.modifiers)
2186         self.entry.inline_func_in_pxd = self.inline_in_pxd
2187         self.return_type = type.return_type
2188         if self.return_type.is_array and self.visibility != 'extern':
2189             error(self.pos,
2190                 "Function cannot return an array")
2191         if self.return_type.is_cpp_class:
2192             self.return_type.check_nullary_constructor(self.pos, "used as a return value")
2193
2194         if self.overridable and not env.is_module_scope:
2195             if len(self.args) < 1 or not self.args[0].type.is_pyobject:
2196                 # An error will be produced in the cdef function
2197                 self.overridable = False
2198
2199         self.declare_cpdef_wrapper(env)
2200         self.create_local_scope(env)
2201
2202     def declare_cpdef_wrapper(self, env):
2203         if self.overridable:
2204             name = self.entry.name
2205             py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
2206             self.py_func = DefNode(pos = self.pos,
2207                                    name = self.entry.name,
2208                                    args = self.args,
2209                                    star_arg = None,
2210                                    starstar_arg = None,
2211                                    doc = self.doc,
2212                                    body = py_func_body,
2213                                    is_wrapper = 1)
2214             self.py_func.is_module_scope = env.is_module_scope
2215             self.py_func.analyse_declarations(env)
2216             self.entry.as_variable = self.py_func.entry
2217             self.entry.used = self.entry.as_variable.used = True
2218             # Reset scope entry the above cfunction
2219             env.entries[name] = self.entry
2220             if (not self.entry.is_final_cmethod and
2221                 (not env.is_module_scope or Options.lookup_module_cpdef)):
2222                 self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
2223                 self.body = StatListNode(self.pos, stats=[self.override, self.body])
2224
2225     def _validate_type_visibility(self, type, pos, env):
2226         """
2227         Ensure that types used in cdef functions are public or api, or
2228         defined in a C header.
2229         """
2230         public_or_api = (self.visibility == 'public' or self.api)
2231         entry = getattr(type, 'entry', None)
2232         if public_or_api and entry and env.is_module_scope:
2233             if not (entry.visibility in ('public', 'extern') or
2234                     entry.api or entry.in_cinclude):
2235                 error(pos, "Function declared public or api may not have "
2236                            "private types")
2237
2238     def call_self_node(self, omit_optional_args=0, is_module_scope=0):
2239         import ExprNodes
2240         args = self.type.args
2241         if omit_optional_args:
2242             args = args[:len(args) - self.type.optional_arg_count]
2243         arg_names = [arg.name for arg in args]
2244         if is_module_scope:
2245             cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
2246         else:
2247             self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
2248             cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
2249         skip_dispatch = not is_module_scope or Options.lookup_module_cpdef
2250         c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names[1-is_module_scope:]], wrapper_call=skip_dispatch)
2251         return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
2252
2253     def declare_arguments(self, env):
2254         for arg in self.type.args:
2255             if not arg.name:
2256                 error(arg.pos, "Missing argument name")
2257             self.declare_argument(env, arg)
2258
2259     def need_gil_acquisition(self, lenv):
2260         return self.type.with_gil
2261
2262     def nogil_check(self, env):
2263         type = self.type
2264         with_gil = type.with_gil
2265         if type.nogil and not with_gil:
2266             if type.return_type.is_pyobject:
2267                 error(self.pos,
2268                       "Function with Python return type cannot be declared nogil")
2269             for entry in self.local_scope.var_entries:
2270                 if entry.type.is_pyobject and not entry.in_with_gil_block:
2271                     error(self.pos, "Function declared nogil has Python locals or temporaries")
2272
2273     def analyse_expressions(self, env):
2274         self.local_scope.directives = env.directives
2275         if self.py_func is not None:
2276             # this will also analyse the default values
2277             self.py_func = self.py_func.analyse_expressions(env)
2278         else:
2279             self.analyse_default_values(env)
2280         self.acquire_gil = self.need_gil_acquisition(self.local_scope)
2281         return self
2282
2283     def needs_assignment_synthesis(self, env, code=None):
2284         return False
2285
2286     def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
2287         scope = self.local_scope
2288         arg_decls = []
2289         type = self.type
2290         for arg in type.args[:len(type.args)-type.optional_arg_count]:
2291             arg_decl = arg.declaration_code()
2292             entry = scope.lookup(arg.name)
2293             if not entry.cf_used:
2294                 arg_decl = 'CYTHON_UNUSED %s' % arg_decl
2295             arg_decls.append(arg_decl)
2296         if with_dispatch and self.overridable:
2297             dispatch_arg = PyrexTypes.c_int_type.declaration_code(
2298                 Naming.skip_dispatch_cname)
2299             if self.override:
2300                 arg_decls.append(dispatch_arg)
2301             else:
2302                 arg_decls.append('CYTHON_UNUSED %s' % dispatch_arg)
2303         if type.optional_arg_count and with_opt_args:
2304             arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
2305         if type.has_varargs:
2306             arg_decls.append("...")
2307         if not arg_decls:
2308             arg_decls = ["void"]
2309         if cname is None:
2310             cname = self.entry.func_cname
2311         entity = type.function_header_code(cname, ', '.join(arg_decls))
2312         if self.entry.visibility == 'private' and '::' not in cname:
2313             storage_class = "static "
2314         else:
2315             storage_class = ""
2316         dll_linkage = None
2317         modifiers = code.build_function_modifiers(self.entry.func_modifiers)
2318
2319         header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
2320         #print (storage_class, modifiers, header)
2321         if self.template_declaration:
2322             code.putln(self.template_declaration)
2323         code.putln("%s%s%s {" % (storage_class, modifiers, header))
2324
2325     def generate_argument_declarations(self, env, code):
2326         scope = self.local_scope
2327         for arg in self.args:
2328             if arg.default:
2329                 entry = scope.lookup(arg.name)
2330                 if self.override or entry.cf_used:
2331                     result = arg.calculate_default_value_code(code)
2332                     code.putln('%s = %s;' % (
2333                         arg.type.declaration_code(arg.cname), result))
2334
2335     def generate_keyword_list(self, code):
2336         pass
2337
2338     def generate_argument_parsing_code(self, env, code):
2339         i = 0
2340         used = 0
2341         if self.type.optional_arg_count:
2342             scope = self.local_scope
2343             code.putln('if (%s) {' % Naming.optional_args_cname)
2344             for arg in self.args:
2345                 if arg.default:
2346                     entry = scope.lookup(arg.name)
2347                     if self.override or entry.cf_used:
2348                         code.putln('if (%s->%sn > %s) {' %
2349                                    (Naming.optional_args_cname,
2350                                     Naming.pyrex_prefix, i))
2351                         declarator = arg.declarator
2352                         while not hasattr(declarator, 'name'):
2353                             declarator = declarator.base
2354                         code.putln('%s = %s->%s;' %
2355                                    (arg.cname, Naming.optional_args_cname,
2356                                     self.type.opt_arg_cname(declarator.name)))
2357                         used += 1
2358                     i += 1
2359             for _ in range(used):
2360                 code.putln('}')
2361             code.putln('}')
2362
2363     def generate_argument_conversion_code(self, code):
2364         pass
2365
2366     def generate_argument_type_tests(self, code):
2367         # Generate type tests for args whose type in a parent
2368         # class is a supertype of the declared type.
2369         for arg in self.type.args:
2370             if arg.needs_type_test:
2371                 self.generate_arg_type_test(arg, code)
2372             elif arg.type.is_pyobject and not arg.accept_none:
2373                 self.generate_arg_none_check(arg, code)
2374
2375     def error_value(self):
2376         if self.return_type.is_pyobject:
2377             return "0"
2378         else:
2379             #return None
2380             return self.entry.type.exception_value
2381
2382     def caller_will_check_exceptions(self):
2383         return self.entry.type.exception_check
2384
2385     def generate_wrapper_functions(self, code):
2386         # If the C signature of a function has changed, we need to generate
2387         # wrappers to put in the slots here.
2388         k = 0
2389         entry = self.entry
2390         func_type = entry.type
2391         while entry.prev_entry is not None:
2392             k += 1
2393             entry = entry.prev_entry
2394             entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
2395             code.putln()
2396             self.generate_function_header(code,
2397                                           0,
2398                                           with_dispatch = entry.type.is_overridable,
2399                                           with_opt_args = entry.type.optional_arg_count,
2400                                           cname = entry.func_cname)
2401             if not self.return_type.is_void:
2402                 code.put('return ')
2403             args = self.type.args
2404             arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
2405             if entry.type.is_overridable:
2406                 arglist.append(Naming.skip_dispatch_cname)
2407             elif func_type.is_overridable:
2408                 arglist.append('0')
2409             if entry.type.optional_arg_count:
2410                 arglist.append(Naming.optional_args_cname)
2411             elif func_type.optional_arg_count:
2412                 arglist.append('NULL')
2413             code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
2414             code.putln('}')
2415
2416
2417 class PyArgDeclNode(Node):
2418     # Argument which must be a Python object (used
2419     # for * and ** arguments).
2420     #
2421     # name        string
2422     # entry       Symtab.Entry
2423     # annotation  ExprNode or None   Py3 argument annotation
2424     child_attrs = []
2425     is_self_arg = False
2426     is_type_arg = False
2427
2428     def generate_function_definitions(self, env, code):
2429         self.entry.generate_function_definitions(env, code)
2430
2431 class DecoratorNode(Node):
2432     # A decorator
2433     #
2434     # decorator    NameNode or CallNode or AttributeNode
2435     child_attrs = ['decorator']
2436
2437
2438 class DefNode(FuncDefNode):
2439     # A Python function definition.
2440     #
2441     # name          string                 the Python name of the function
2442     # lambda_name   string                 the internal name of a lambda 'function'
2443     # decorators    [DecoratorNode]        list of decorators
2444     # args          [CArgDeclNode]         formal arguments
2445     # doc           EncodedString or None
2446     # body          StatListNode
2447     # return_type_annotation
2448     #               ExprNode or None       the Py3 return type annotation
2449     #
2450     #  The following subnode is constructed internally
2451     #  when the def statement is inside a Python class definition.
2452     #
2453     #  fused_py_func        DefNode     The original fused cpdef DefNode
2454     #                                   (in case this is a specialization)
2455     #  specialized_cpdefs   [DefNode]   list of specialized cpdef DefNodes
2456     #  py_cfunc_node  PyCFunctionNode/InnerFunctionNode   The PyCFunction to create and assign
2457     #
2458     # decorator_indirection IndirectionNode Used to remove __Pyx_Method_ClassMethod for fused functions
2459
2460     child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
2461
2462     lambda_name = None
2463     reqd_kw_flags_cname = "0"
2464     is_wrapper = 0
2465     no_assignment_synthesis = 0
2466     decorators = None
2467     return_type_annotation = None
2468     entry = None
2469     acquire_gil = 0
2470     self_in_stararg = 0
2471     py_cfunc_node = None
2472     requires_classobj = False
2473     defaults_struct = None # Dynamic kwrds structure name
2474     doc = None
2475
2476     fused_py_func = False
2477     specialized_cpdefs = None
2478     py_wrapper = None
2479     py_wrapper_required = True
2480     func_cname = None
2481
2482     defaults_getter = None
2483
2484     def __init__(self, pos, **kwds):
2485         FuncDefNode.__init__(self, pos, **kwds)
2486         k = rk = r = 0
2487         for arg in self.args:
2488             if arg.kw_only:
2489                 k += 1
2490                 if not arg.default:
2491                     rk += 1
2492             if not arg.default:
2493                 r += 1
2494         self.num_kwonly_args = k
2495         self.num_required_kw_args = rk
2496         self.num_required_args = r
2497
2498     def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None):
2499         if self.star_arg:
2500             error(self.star_arg.pos, "cdef function cannot have star argument")
2501         if self.starstar_arg:
2502             error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
2503         if cfunc is None:
2504             cfunc_args = []
2505             for formal_arg in self.args:
2506                 name_declarator, type = formal_arg.analyse(scope, nonempty=1)
2507                 cfunc_args.append(PyrexTypes.CFuncTypeArg(name = name_declarator.name,
2508                                                           cname = None,
2509                                                           type = py_object_type,
2510                                                           pos = formal_arg.pos))
2511             cfunc_type = PyrexTypes.CFuncType(return_type = py_object_type,
2512                                               args = cfunc_args,
2513                                               has_varargs = False,
2514                                               exception_value = None,
2515                                               exception_check = False,
2516                                               nogil = False,
2517                                               with_gil = False,
2518                                               is_overridable = overridable)
2519             cfunc = CVarDefNode(self.pos, type=cfunc_type)
2520         else:
2521             if scope is None:
2522                 scope = cfunc.scope
2523             cfunc_type = cfunc.type
2524             if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
2525                 error(self.pos, "wrong number of arguments")
2526                 error(cfunc.pos, "previous declaration here")
2527             for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)):
2528                 name_declarator, type = formal_arg.analyse(scope, nonempty=1,
2529                                                            is_self_arg = (i == 0 and scope.is_c_class_scope))
2530                 if type is None or type is PyrexTypes.py_object_type:
2531                     formal_arg.type = type_arg.type
2532                     formal_arg.name_declarator = name_declarator
2533         import ExprNodes
2534         if cfunc_type.exception_value is None:
2535             exception_value = None
2536         else:
2537             exception_value = ExprNodes.ConstNode(self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type)
2538         declarator = CFuncDeclaratorNode(self.pos,
2539                                          base = CNameDeclaratorNode(self.pos, name=self.name, cname=None),
2540                                          args = self.args,
2541                                          has_varargs = False,
2542                                          exception_check = cfunc_type.exception_check,
2543                                          exception_value = exception_value,
2544                                          with_gil = cfunc_type.with_gil,
2545                                          nogil = cfunc_type.nogil)
2546         return CFuncDefNode(self.pos,
2547                             modifiers = [],
2548                             base_type = CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type),
2549                             declarator = declarator,
2550                             body = self.body,
2551                             doc = self.doc,
2552                             overridable = cfunc_type.is_overridable,
2553                             type = cfunc_type,
2554                             with_gil = cfunc_type.with_gil,
2555                             nogil = cfunc_type.nogil,
2556                             visibility = 'private',
2557                             api = False,
2558                             directive_locals = getattr(cfunc, 'directive_locals', {}),
2559                             directive_returns = returns)
2560
2561     def is_cdef_func_compatible(self):
2562         """Determines if the function's signature is compatible with a
2563         cdef function.  This can be used before calling
2564         .as_cfunction() to see if that will be successful.
2565         """
2566         if self.needs_closure:
2567             return False
2568         if self.star_arg or self.starstar_arg:
2569             return False
2570         return True
2571
2572     def analyse_declarations(self, env):
2573         self.is_classmethod = self.is_staticmethod = False
2574         if self.decorators:
2575             for decorator in self.decorators:
2576                 func = decorator.decorator
2577                 if func.is_name:
2578                     self.is_classmethod |= func.name == 'classmethod'
2579                     self.is_staticmethod |= func.name == 'staticmethod'
2580
2581         if self.is_classmethod and env.lookup_here('classmethod'):
2582             # classmethod() was overridden - not much we can do here ...
2583             self.is_classmethod = False
2584         if self.is_staticmethod and env.lookup_here('staticmethod'):
2585             # staticmethod() was overridden - not much we can do here ...
2586             self.is_staticmethod = False
2587
2588         if self.name == '__new__' and env.is_py_class_scope:
2589             self.is_staticmethod = 1
2590
2591         self.analyse_argument_types(env)
2592         if self.name == '<lambda>':
2593             self.declare_lambda_function(env)
2594         else:
2595             self.declare_pyfunction(env)
2596
2597         self.analyse_signature(env)
2598         self.return_type = self.entry.signature.return_type()
2599         self.create_local_scope(env)
2600
2601         self.py_wrapper = DefNodeWrapper(
2602             self.pos,
2603             target=self,
2604             name=self.entry.name,
2605             args=self.args,
2606             star_arg=self.star_arg,
2607             starstar_arg=self.starstar_arg,
2608             return_type=self.return_type)
2609         self.py_wrapper.analyse_declarations(env)
2610
2611     def analyse_argument_types(self, env):
2612         self.directive_locals = env.directives['locals']
2613         allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
2614
2615         f2s = env.fused_to_specific
2616         env.fused_to_specific = None
2617
2618         for arg in self.args:
2619             if hasattr(arg, 'name'):
2620                 name_declarator = None
2621             else:
2622                 base_type = arg.base_type.analyse(env)
2623                 name_declarator, type = \
2624                     arg.declarator.analyse(base_type, env)
2625                 arg.name = name_declarator.name
2626                 arg.type = type
2627
2628                 if type.is_fused:
2629                     self.has_fused_arguments = True
2630
2631             self.align_argument_type(env, arg)
2632             if name_declarator and name_declarator.cname:
2633                 error(self.pos,
2634                     "Python function argument cannot have C name specification")
2635             arg.type = arg.type.as_argument_type()
2636             arg.hdr_type = None
2637             arg.needs_conversion = 0
2638             arg.needs_type_test = 0
2639             arg.is_generic = 1
2640             if arg.type.is_pyobject or arg.type.is_buffer or arg.type.is_memoryviewslice:
2641                 if arg.or_none:
2642                     arg.accept_none = True
2643                 elif arg.not_none:
2644                     arg.accept_none = False
2645                 elif (arg.type.is_extension_type or arg.type.is_builtin_type
2646                       or arg.type.is_buffer or arg.type.is_memoryviewslice):
2647                     if arg.default and arg.default.constant_result is None:
2648                         # special case: def func(MyType obj = None)
2649                         arg.accept_none = True
2650                     else:
2651                         # default depends on compiler directive
2652                         arg.accept_none = allow_none_for_extension_args
2653                 else:
2654                     # probably just a plain 'object'
2655                     arg.accept_none = True
2656             else:
2657                 arg.accept_none = True # won't be used, but must be there
2658                 if arg.not_none:
2659                     error(arg.pos, "Only Python type arguments can have 'not None'")
2660                 if arg.or_none:
2661                     error(arg.pos, "Only Python type arguments can have 'or None'")
2662
2663         env.fused_to_specific = f2s
2664
2665     def analyse_signature(self, env):
2666         if self.entry.is_special:
2667             if self.decorators:
2668                 error(self.pos, "special functions of cdef classes cannot have decorators")
2669             self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
2670         elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
2671             # Use the simpler calling signature for zero- and one-argument functions.
2672             if self.entry.signature is TypeSlots.pyfunction_signature:
2673                 if len(self.args) == 0:
2674                     self.entry.signature = TypeSlots.pyfunction_noargs
2675                 elif len(self.args) == 1:
2676                     if self.args[0].default is None and not self.args[0].kw_only:
2677                         self.entry.signature = TypeSlots.pyfunction_onearg
2678             elif self.entry.signature is TypeSlots.pymethod_signature:
2679                 if len(self.args) == 1:
2680                     self.entry.signature = TypeSlots.unaryfunc
2681                 elif len(self.args) == 2:
2682                     if self.args[1].default is None and not self.args[1].kw_only:
2683                         self.entry.signature = TypeSlots.ibinaryfunc
2684
2685         sig = self.entry.signature
2686         nfixed = sig.num_fixed_args()
2687         if sig is TypeSlots.pymethod_signature and nfixed == 1 \
2688                and len(self.args) == 0 and self.star_arg:
2689             # this is the only case where a diverging number of
2690             # arguments is not an error - when we have no explicit
2691             # 'self' parameter as in method(*args)
2692             sig = self.entry.signature = TypeSlots.pyfunction_signature # self is not 'really' used
2693             self.self_in_stararg = 1
2694             nfixed = 0
2695
2696         if self.is_staticmethod and env.is_c_class_scope:
2697             nfixed = 0
2698             self.self_in_stararg = True  # FIXME: why for staticmethods?
2699
2700             self.entry.signature = sig = copy.copy(sig)
2701             sig.fixed_arg_format = "*"
2702             sig.is_staticmethod = True
2703             sig.has_generic_args = True
2704
2705         if ((self.is_classmethod or self.is_staticmethod) and
2706             self.has_fused_arguments and env.is_c_class_scope):
2707             del self.decorator_indirection.stats[:]
2708
2709         for i in range(min(nfixed, len(self.args))):
2710             arg = self.args[i]
2711             arg.is_generic = 0
2712             if sig.is_self_arg(i) and not self.is_staticmethod:
2713                 if self.is_classmethod:
2714                     arg.is_type_arg = 1
2715                     arg.hdr_type = arg.type = Builtin.type_type
2716                 else:
2717                     arg.is_self_arg = 1
2718                     arg.hdr_type = arg.type = env.parent_type
2719                 arg.needs_conversion = 0
2720             else:
2721                 arg.hdr_type = sig.fixed_arg_type(i)
2722                 if not arg.type.same_as(arg.hdr_type):
2723                     if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
2724                         arg.needs_type_test = 1
2725                     else:
2726                         arg.needs_conversion = 1
2727             if arg.needs_conversion:
2728                 arg.hdr_cname = Naming.arg_prefix + arg.name
2729             else:
2730                 arg.hdr_cname = Naming.var_prefix + arg.name
2731
2732         if nfixed > len(self.args):
2733             self.bad_signature()
2734             return
2735         elif nfixed < len(self.args):
2736             if not sig.has_generic_args:
2737                 self.bad_signature()
2738             for arg in self.args:
2739                 if arg.is_generic and \
2740                         (arg.type.is_extension_type or arg.type.is_builtin_type):
2741                     arg.needs_type_test = 1
2742
2743     def bad_signature(self):
2744         sig = self.entry.signature
2745         expected_str = "%d" % sig.num_fixed_args()
2746         if sig.has_generic_args:
2747             expected_str += " or more"
2748         name = self.name
2749         if name.startswith("__") and name.endswith("__"):
2750             desc = "Special method"
2751         else:
2752             desc = "Method"
2753         error(self.pos,
2754             "%s %s has wrong number of arguments "
2755             "(%d declared, %s expected)" % (
2756                 desc, self.name, len(self.args), expected_str))
2757
2758     def declare_pyfunction(self, env):
2759         #print "DefNode.declare_pyfunction:", self.name, "in", env ###
2760         name = self.name
2761         entry = env.lookup_here(name)
2762         if entry:
2763             if entry.is_final_cmethod and not env.parent_type.is_final_type:
2764                 error(self.pos, "Only final types can have final Python (def/cpdef) methods")
2765             if (entry.type.is_cfunction and not entry.is_builtin_cmethod
2766                 and not self.is_wrapper):
2767                 warning(self.pos, "Overriding cdef method with def method.", 5)
2768         entry = env.declare_pyfunction(name, self.pos, allow_redefine=not self.is_wrapper)
2769         self.entry = entry
2770         prefix = env.next_id(env.scope_prefix)
2771         self.entry.pyfunc_cname = Naming.pyfunc_prefix + prefix + name
2772         if Options.docstrings:
2773             entry.doc = embed_position(self.pos, self.doc)
2774             entry.doc_cname = Naming.funcdoc_prefix + prefix + name
2775             if entry.is_special:
2776                 if entry.name in TypeSlots.invisible or not entry.doc or (entry.name in '__getattr__' and env.directives['fast_getattr']):
2777                     entry.wrapperbase_cname = None
2778                 else:
2779                     entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
2780         else:
2781             entry.doc = None
2782
2783     def declare_lambda_function(self, env):
2784         entry = env.declare_lambda_function(self.lambda_name, self.pos)
2785         entry.doc = None
2786         self.entry = entry
2787         self.entry.pyfunc_cname = entry.cname
2788
2789     def declare_arguments(self, env):
2790         for arg in self.args:
2791             if not arg.name:
2792                 error(arg.pos, "Missing argument name")
2793             if arg.needs_conversion:
2794                 arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
2795                 if arg.type.is_pyobject:
2796                     arg.entry.init = "0"
2797             else:
2798                 arg.entry = self.declare_argument(env, arg)
2799             arg.entry.is_arg = 1
2800             arg.entry.used = 1
2801             arg.entry.is_self_arg = arg.is_self_arg
2802         self.declare_python_arg(env, self.star_arg)
2803         self.declare_python_arg(env, self.starstar_arg)
2804
2805     def declare_python_arg(self, env, arg):
2806         if arg:
2807             if env.directives['infer_types'] != False:
2808                 type = PyrexTypes.unspecified_type
2809             else:
2810                 type = py_object_type
2811             entry = env.declare_var(arg.name, type, arg.pos)
2812             entry.is_arg = 1
2813             entry.used = 1
2814             entry.init = "0"
2815             entry.xdecref_cleanup = 1
2816             arg.entry = entry
2817
2818     def analyse_expressions(self, env):
2819         self.local_scope.directives = env.directives
2820         self.analyse_default_values(env)
2821
2822         if not self.needs_assignment_synthesis(env) and self.decorators:
2823             for decorator in self.decorators[::-1]:
2824                 decorator.decorator = decorator.decorator.analyse_expressions(env)
2825
2826         self.py_wrapper.prepare_argument_coercion(env)
2827         return self
2828
2829     def needs_assignment_synthesis(self, env, code=None):
2830         if self.is_wrapper or self.specialized_cpdefs or self.entry.is_fused_specialized:
2831             return False
2832         if self.is_staticmethod:
2833             return True
2834         if self.no_assignment_synthesis:
2835             return False
2836         # Should enable for module level as well, that will require more testing...
2837         if self.entry.is_anonymous:
2838             return True
2839         if env.is_module_scope:
2840             if code is None:
2841                 return env.directives['binding']
2842             else:
2843                 return code.globalstate.directives['binding']
2844         return env.is_py_class_scope or env.is_closure_scope
2845
2846     def error_value(self):
2847         return self.entry.signature.error_value
2848
2849     def caller_will_check_exceptions(self):
2850         return self.entry.signature.exception_check
2851
2852     def generate_function_definitions(self, env, code):
2853         if self.defaults_getter:
2854             self.defaults_getter.generate_function_definitions(env, code)
2855
2856         # Before closure cnames are mangled
2857         if self.py_wrapper_required:
2858             # func_cname might be modified by @cname
2859             self.py_wrapper.func_cname = self.entry.func_cname
2860             self.py_wrapper.generate_function_definitions(env, code)
2861         FuncDefNode.generate_function_definitions(self, env, code)
2862
2863     def generate_function_header(self, code, with_pymethdef, proto_only=0):
2864         if proto_only:
2865             if self.py_wrapper_required:
2866                 self.py_wrapper.generate_function_header(
2867                     code, with_pymethdef, True)
2868             return
2869         arg_code_list = []
2870         if self.entry.signature.has_dummy_arg:
2871             self_arg = 'PyObject *%s' % Naming.self_cname
2872             if not self.needs_outer_scope:
2873                 self_arg = 'CYTHON_UNUSED ' + self_arg
2874             arg_code_list.append(self_arg)
2875
2876         def arg_decl_code(arg):
2877             entry = arg.entry
2878             if entry.in_closure:
2879                 cname = entry.original_cname
2880             else:
2881                 cname = entry.cname
2882             decl = entry.type.declaration_code(cname)
2883             if not entry.cf_used:
2884                 decl = 'CYTHON_UNUSED ' + decl
2885             return decl
2886
2887         for arg in self.args:
2888             arg_code_list.append(arg_decl_code(arg))
2889         if self.star_arg:
2890             arg_code_list.append(arg_decl_code(self.star_arg))
2891         if self.starstar_arg:
2892             arg_code_list.append(arg_decl_code(self.starstar_arg))
2893         arg_code = ', '.join(arg_code_list)
2894         dc = self.return_type.declaration_code(self.entry.pyfunc_cname)
2895
2896         decls_code = code.globalstate['decls']
2897         preprocessor_guard = self.get_preprocessor_guard()
2898         if preprocessor_guard:
2899             decls_code.putln(preprocessor_guard)
2900         decls_code.putln(
2901             "static %s(%s); /* proto */" % (dc, arg_code))
2902         if preprocessor_guard:
2903             decls_code.putln("#endif")
2904         code.putln("static %s(%s) {" % (dc, arg_code))
2905
2906     def generate_argument_declarations(self, env, code):
2907         pass
2908
2909     def generate_keyword_list(self, code):
2910         pass
2911
2912     def generate_argument_parsing_code(self, env, code):
2913         # Move arguments into closure if required
2914         def put_into_closure(entry):
2915             if entry.in_closure:
2916                 code.putln('%s = %s;' % (entry.cname, entry.original_cname))
2917                 code.put_var_incref(entry)
2918                 code.put_var_giveref(entry)
2919         for arg in self.args:
2920             put_into_closure(arg.entry)
2921         for arg in self.star_arg, self.starstar_arg:
2922             if arg:
2923                 put_into_closure(arg.entry)
2924
2925     def generate_argument_type_tests(self, code):
2926         pass
2927
2928
2929 class DefNodeWrapper(FuncDefNode):
2930     # DefNode python wrapper code generator
2931
2932     defnode = None
2933     target = None # Target DefNode
2934
2935     def __init__(self, *args, **kwargs):
2936         FuncDefNode.__init__(self, *args, **kwargs)
2937         self.num_kwonly_args = self.target.num_kwonly_args
2938         self.num_required_kw_args = self.target.num_required_kw_args
2939         self.num_required_args = self.target.num_required_args
2940         self.self_in_stararg = self.target.self_in_stararg
2941         self.signature = None
2942
2943     def analyse_declarations(self, env):
2944         target_entry = self.target.entry
2945         name = self.name
2946         prefix = env.next_id(env.scope_prefix)
2947         target_entry.func_cname = Naming.pywrap_prefix + prefix + name
2948         target_entry.pymethdef_cname = Naming.pymethdef_prefix + prefix + name
2949
2950         self.signature = target_entry.signature
2951
2952     def prepare_argument_coercion(self, env):
2953         # This is only really required for Cython utility code at this time,
2954         # everything else can be done during code generation.  But we expand
2955         # all utility code here, simply because we cannot easily distinguish
2956         # different code types.
2957         for arg in self.args:
2958             if not arg.type.is_pyobject:
2959                 if not arg.type.create_from_py_utility_code(env):
2960                     pass # will fail later
2961             elif arg.hdr_type and not arg.hdr_type.is_pyobject:
2962                 if not arg.hdr_type.create_to_py_utility_code(env):
2963                     pass # will fail later
2964
2965     def signature_has_nongeneric_args(self):
2966         argcount = len(self.args)
2967         if argcount == 0 or (
2968                 argcount == 1 and (self.args[0].is_self_arg or
2969                                    self.args[0].is_type_arg)):
2970             return 0
2971         return 1
2972
2973     def signature_has_generic_args(self):
2974         return self.signature.has_generic_args
2975
2976     def generate_function_body(self, code):
2977         args = []
2978         if self.signature.has_dummy_arg:
2979             args.append(Naming.self_cname)
2980         for arg in self.args:
2981             if arg.hdr_type and not (arg.type.is_memoryviewslice or
2982                                      arg.type.is_struct or
2983                                      arg.type.is_complex):
2984                 args.append(arg.type.cast_code(arg.entry.cname))
2985             else:
2986                 args.append(arg.entry.cname)
2987         if self.star_arg:
2988             args.append(self.star_arg.entry.cname)
2989         if self.starstar_arg:
2990             args.append(self.starstar_arg.entry.cname)
2991         args = ', '.join(args)
2992         if not self.return_type.is_void:
2993             code.put('%s = ' % Naming.retval_cname)
2994         code.putln('%s(%s);' % (
2995             self.target.entry.pyfunc_cname, args))
2996
2997     def generate_function_definitions(self, env, code):
2998         lenv = self.target.local_scope
2999         # Generate C code for header and body of function
3000         code.mark_pos(self.pos)
3001         code.putln("")
3002         code.putln("/* Python wrapper */")
3003         preprocessor_guard = self.target.get_preprocessor_guard()
3004         if preprocessor_guard:
3005             code.putln(preprocessor_guard)
3006
3007         code.enter_cfunc_scope()
3008         code.return_from_error_cleanup_label = code.new_label()
3009
3010         with_pymethdef = (self.target.needs_assignment_synthesis(env, code) or
3011                           self.target.pymethdef_required)
3012         self.generate_function_header(code, with_pymethdef)
3013         self.generate_argument_declarations(lenv, code)
3014         tempvardecl_code = code.insertion_point()
3015
3016         if self.return_type.is_pyobject:
3017             retval_init = ' = 0'
3018         else:
3019             retval_init = ''
3020         if not self.return_type.is_void:
3021             code.putln('%s%s;' % (
3022                 self.return_type.declaration_code(Naming.retval_cname),
3023                 retval_init))
3024         code.put_declare_refcount_context()
3025         code.put_setup_refcount_context('%s (wrapper)' % self.name)
3026
3027         self.generate_argument_parsing_code(lenv, code)
3028         self.generate_argument_type_tests(code)
3029         self.generate_function_body(code)
3030
3031         # ----- Go back and insert temp variable declarations
3032         tempvardecl_code.put_temp_declarations(code.funcstate)
3033
3034         code.mark_pos(self.pos)
3035         code.putln("")
3036         code.putln("/* function exit code */")
3037
3038         # ----- Error cleanup
3039         if code.error_label in code.labels_used:
3040             code.put_goto(code.return_label)
3041             code.put_label(code.error_label)
3042             for cname, type in code.funcstate.all_managed_temps():
3043                 code.put_xdecref(cname, type)
3044             err_val = self.error_value()
3045             if err_val is not None:
3046                 code.putln("%s = %s;" % (Naming.retval_cname, err_val))
3047
3048         # ----- Non-error return cleanup
3049         code.put_label(code.return_label)
3050         for entry in lenv.var_entries:
3051             if entry.is_arg and entry.type.is_pyobject:
3052                 code.put_var_decref(entry)
3053
3054         code.put_finish_refcount_context()
3055         if not self.return_type.is_void:
3056             code.putln("return %s;" % Naming.retval_cname)
3057         code.putln('}')
3058         code.exit_cfunc_scope()
3059         if preprocessor_guard:
3060             code.putln("#endif /*!(%s)*/" % preprocessor_guard)
3061
3062     def generate_function_header(self, code, with_pymethdef, proto_only=0):
3063         arg_code_list = []
3064         sig = self.signature
3065
3066         if sig.has_dummy_arg or self.self_in_stararg:
3067             arg_code = "PyObject *%s" % Naming.self_cname
3068             if not sig.has_dummy_arg:
3069                 arg_code = 'CYTHON_UNUSED ' + arg_code
3070             arg_code_list.append(arg_code)
3071
3072         for arg in self.args:
3073             if not arg.is_generic:
3074                 if arg.is_self_arg or arg.is_type_arg:
3075                     arg_code_list.append("PyObject *%s" % arg.hdr_cname)
3076                 else:
3077                     arg_code_list.append(
3078                         arg.hdr_type.declaration_code(arg.hdr_cname))
3079         entry = self.target.entry
3080         if not entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
3081             arg_code_list.append("CYTHON_UNUSED PyObject *unused")
3082         if entry.scope.is_c_class_scope and entry.name == "__ipow__":
3083             arg_code_list.append("CYTHON_UNUSED PyObject *unused")
3084         if sig.has_generic_args:
3085             arg_code_list.append(
3086                 "PyObject *%s, PyObject *%s"
3087                     % (Naming.args_cname, Naming.kwds_cname))
3088         arg_code = ", ".join(arg_code_list)
3089
3090         # Prevent warning: unused function '__pyx_pw_5numpy_7ndarray_1__getbuffer__'
3091         mf = ""
3092         if (entry.name in ("__getbuffer__", "__releasebuffer__")
3093             and entry.scope.is_c_class_scope):
3094             mf = "CYTHON_UNUSED "
3095             with_pymethdef = False
3096
3097         dc = self.return_type.declaration_code(entry.func_cname)
3098         header = "static %s%s(%s)" % (mf, dc, arg_code)
3099         code.putln("%s; /*proto*/" % header)
3100
3101         if proto_only:
3102             if self.target.fused_py_func:
3103                 # If we are the specialized version of the cpdef, we still
3104                 # want the prototype for the "fused cpdef", in case we're
3105                 # checking to see if our method was overridden in Python
3106                 self.target.fused_py_func.generate_function_header(
3107                                     code, with_pymethdef, proto_only=True)
3108             return
3109
3110         if (Options.docstrings and entry.doc and
3111                 not self.target.fused_py_func and
3112                 not entry.scope.is_property_scope and
3113                 (not entry.is_special or entry.wrapperbase_cname)):
3114             # h_code = code.globalstate['h_code']
3115             docstr = entry.doc
3116
3117             if docstr.is_unicode:
3118                 docstr = docstr.utf8encode()
3119
3120             code.putln(
3121                 'static char %s[] = "%s";' % (
3122                     entry.doc_cname,
3123                     split_string_literal(escape_byte_string(docstr))))
3124
3125             if entry.is_special:
3126                 code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
3127                 code.putln(
3128                     "struct wrapperbase %s;" % entry.wrapperbase_cname)
3129                 code.putln('#endif')
3130
3131         if with_pymethdef or self.target.fused_py_func:
3132             code.put(
3133                 "static PyMethodDef %s = " %
3134                     entry.pymethdef_cname)
3135             code.put_pymethoddef(self.target.entry, ";", allow_skip=False)
3136         code.putln("%s {" % header)
3137
3138     def generate_argument_declarations(self, env, code):
3139         for arg in self.args:
3140             if arg.is_generic:
3141                 if arg.needs_conversion:
3142                     code.putln("PyObject *%s = 0;" % arg.hdr_cname)
3143                 else:
3144                     code.put_var_declaration(arg.entry)
3145         for entry in env.var_entries:
3146             if entry.is_arg:
3147                 code.put_var_declaration(entry)
3148
3149     def generate_argument_parsing_code(self, env, code):
3150         # Generate fast equivalent of PyArg_ParseTuple call for
3151         # generic arguments, if any, including args/kwargs
3152         old_error_label = code.new_error_label()
3153         our_error_label = code.error_label
3154         end_label = code.new_label("argument_unpacking_done")
3155
3156         has_kwonly_args = self.num_kwonly_args > 0
3157         has_star_or_kw_args = self.star_arg is not None \
3158             or self.starstar_arg is not None or has_kwonly_args
3159
3160         for arg in self.args:
3161             if not arg.type.is_pyobject:
3162                 if not arg.type.create_from_py_utility_code(env):
3163                     pass # will fail later
3164
3165         if not self.signature_has_generic_args():
3166             if has_star_or_kw_args:
3167                 error(self.pos, "This method cannot have * or keyword arguments")
3168             self.generate_argument_conversion_code(code)
3169
3170         elif not self.signature_has_nongeneric_args():
3171             # func(*args) or func(**kw) or func(*args, **kw)
3172             self.generate_stararg_copy_code(code)
3173
3174         else:
3175             self.generate_tuple_and_keyword_parsing_code(self.args, end_label, code)
3176
3177         code.error_label = old_error_label
3178         if code.label_used(our_error_label):
3179             if not code.label_used(end_label):
3180                 code.put_goto(end_label)
3181             code.put_label(our_error_label)
3182             if has_star_or_kw_args:
3183                 self.generate_arg_decref(self.star_arg, code)
3184                 if self.starstar_arg:
3185                     if self.starstar_arg.entry.xdecref_cleanup:
3186                         code.put_var_xdecref_clear(self.starstar_arg.entry)
3187                     else:
3188                         code.put_var_decref_clear(self.starstar_arg.entry)
3189             code.put_add_traceback(self.target.entry.qualified_name)
3190             code.put_finish_refcount_context()
3191             code.putln("return %s;" % self.error_value())
3192         if code.label_used(end_label):
3193             code.put_label(end_label)
3194
3195     def generate_arg_xdecref(self, arg, code):
3196         if arg:
3197             code.put_var_xdecref_clear(arg.entry)
3198
3199     def generate_arg_decref(self, arg, code):
3200         if arg:
3201             code.put_var_decref_clear(arg.entry)
3202
3203     def generate_stararg_copy_code(self, code):
3204         if not self.star_arg:
3205             code.globalstate.use_utility_code(
3206                 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3207             code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
3208                        Naming.args_cname)
3209             code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
3210                     self.name, Naming.args_cname, self.error_value()))
3211             code.putln("}")
3212
3213         if self.starstar_arg:
3214             if self.star_arg:
3215                 kwarg_check = "unlikely(%s)" % Naming.kwds_cname
3216             else:
3217                 kwarg_check = "%s" % Naming.kwds_cname
3218         else:
3219             kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
3220                 Naming.kwds_cname, Naming.kwds_cname)
3221         code.globalstate.use_utility_code(
3222             UtilityCode.load_cached("KeywordStringCheck", "FunctionArguments.c"))
3223         code.putln(
3224             "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
3225                 kwarg_check, Naming.kwds_cname, self.name,
3226                 bool(self.starstar_arg), self.error_value()))
3227
3228         if self.starstar_arg:
3229             code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
3230                     self.starstar_arg.entry.cname,
3231                     Naming.kwds_cname,
3232                     Naming.kwds_cname))
3233             code.putln("if (unlikely(!%s)) return %s;" % (
3234                     self.starstar_arg.entry.cname, self.error_value()))
3235             self.starstar_arg.entry.xdecref_cleanup = 0
3236             code.put_gotref(self.starstar_arg.entry.cname)
3237
3238         if self.self_in_stararg and not self.target.is_staticmethod:
3239             # need to create a new tuple with 'self' inserted as first item
3240             code.put("%s = PyTuple_New(PyTuple_GET_SIZE(%s)+1); if (unlikely(!%s)) " % (
3241                     self.star_arg.entry.cname,
3242                     Naming.args_cname,
3243                     self.star_arg.entry.cname))
3244             if self.starstar_arg:
3245                 code.putln("{")
3246                 code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
3247                 code.putln("return %s;" % self.error_value())
3248                 code.putln("}")
3249             else:
3250                 code.putln("return %s;" % self.error_value())
3251             code.put_gotref(self.star_arg.entry.cname)
3252             code.put_incref(Naming.self_cname, py_object_type)
3253             code.put_giveref(Naming.self_cname)
3254             code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % (
3255                 self.star_arg.entry.cname, Naming.self_cname))
3256             temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
3257             code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % (
3258                 temp, temp, Naming.args_cname, temp))
3259             code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % (
3260                 Naming.args_cname, temp))
3261             code.put_incref("item", py_object_type)
3262             code.put_giveref("item")
3263             code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % (
3264                 self.star_arg.entry.cname, temp))
3265             code.putln("}")
3266             code.funcstate.release_temp(temp)
3267             self.star_arg.entry.xdecref_cleanup = 0
3268         elif self.star_arg:
3269             code.put_incref(Naming.args_cname, py_object_type)
3270             code.putln("%s = %s;" % (
3271                     self.star_arg.entry.cname,
3272                     Naming.args_cname))
3273             self.star_arg.entry.xdecref_cleanup = 0
3274
3275     def generate_tuple_and_keyword_parsing_code(self, args, success_label, code):
3276         argtuple_error_label = code.new_label("argtuple_error")
3277
3278         positional_args = []
3279         required_kw_only_args = []
3280         optional_kw_only_args = []
3281         for arg in args:
3282             if arg.is_generic:
3283                 if arg.default:
3284                     if not arg.is_self_arg and not arg.is_type_arg:
3285                         if arg.kw_only:
3286                             optional_kw_only_args.append(arg)
3287                         else:
3288                             positional_args.append(arg)
3289                 elif arg.kw_only:
3290                     required_kw_only_args.append(arg)
3291                 elif not arg.is_self_arg and not arg.is_type_arg:
3292                     positional_args.append(arg)
3293
3294         # sort required kw-only args before optional ones to avoid special
3295         # cases in the unpacking code
3296         kw_only_args = required_kw_only_args + optional_kw_only_args
3297
3298         min_positional_args = self.num_required_args - self.num_required_kw_args
3299         if len(args) > 0 and (args[0].is_self_arg or args[0].is_type_arg):
3300             min_positional_args -= 1
3301         max_positional_args = len(positional_args)
3302         has_fixed_positional_count = not self.star_arg and \
3303             min_positional_args == max_positional_args
3304         has_kw_only_args = bool(kw_only_args)
3305
3306         if self.num_required_kw_args:
3307             code.globalstate.use_utility_code(
3308                 UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c"))
3309
3310         if self.starstar_arg or self.star_arg:
3311             self.generate_stararg_init_code(max_positional_args, code)
3312
3313         code.putln('{')
3314         all_args = tuple(positional_args) + tuple(kw_only_args)
3315         code.putln("static PyObject **%s[] = {%s,0};" % (
3316             Naming.pykwdlist_cname,
3317             ','.join([ '&%s' % code.intern_identifier(arg.name)
3318                         for arg in all_args ])))
3319
3320         # Before being converted and assigned to the target variables,
3321         # borrowed references to all unpacked argument values are
3322         # collected into a local PyObject* array called "values",
3323         # regardless if they were taken from default arguments,
3324         # positional arguments or keyword arguments.  Note that
3325         # C-typed default arguments are handled at conversion time,
3326         # so their array value is NULL in the end if no argument
3327         # was passed for them.
3328         self.generate_argument_values_setup_code(all_args, code)
3329
3330         # --- optimised code when we receive keyword arguments
3331         code.putln("if (%s(%s)) {" % (
3332             (self.num_required_kw_args > 0) and "likely" or "unlikely",
3333             Naming.kwds_cname))
3334         self.generate_keyword_unpacking_code(
3335             min_positional_args, max_positional_args,
3336             has_fixed_positional_count, has_kw_only_args,
3337             all_args, argtuple_error_label, code)
3338
3339         # --- optimised code when we do not receive any keyword arguments
3340         if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
3341             # Python raises arg tuple related errors first, so we must
3342             # check the length here
3343             if min_positional_args == max_positional_args and not self.star_arg:
3344                 compare = '!='
3345             else:
3346                 compare = '<'
3347             code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
3348                     Naming.args_cname, compare, min_positional_args))
3349             code.put_goto(argtuple_error_label)
3350
3351         if self.num_required_kw_args:
3352             # pure error case: keywords required but not passed
3353             if max_positional_args > min_positional_args and not self.star_arg:
3354                 code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % (
3355                         Naming.args_cname, max_positional_args))
3356                 code.put_goto(argtuple_error_label)
3357             code.putln('} else {')
3358             for i, arg in enumerate(kw_only_args):
3359                 if not arg.default:
3360                     pystring_cname = code.intern_identifier(arg.name)
3361                     # required keyword-only argument missing
3362                     code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
3363                             self.name,
3364                             pystring_cname))
3365                     code.putln(code.error_goto(self.pos))
3366                     break
3367
3368         else:
3369             # optimised tuple unpacking code
3370             code.putln('} else {')
3371             if min_positional_args == max_positional_args:
3372                 # parse the exact number of positional arguments from
3373                 # the args tuple
3374                 for i, arg in enumerate(positional_args):
3375                     code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
3376             else:
3377                 # parse the positional arguments from the variable length
3378                 # args tuple and reject illegal argument tuple sizes
3379                 code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
3380                 if self.star_arg:
3381                     code.putln('default:')
3382                 reversed_args = list(enumerate(positional_args))[::-1]
3383                 for i, arg in reversed_args:
3384                     if i >= min_positional_args-1:
3385                         code.put('case %2d: ' % (i+1))
3386                     code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
3387                 if min_positional_args == 0:
3388                     code.put('case  0: ')
3389                 code.putln('break;')
3390                 if self.star_arg:
3391                     if min_positional_args:
3392                         for i in range(min_positional_args-1, -1, -1):
3393                             code.putln('case %2d:' % i)
3394                         code.put_goto(argtuple_error_label)
3395                 else:
3396                     code.put('default: ')
3397                     code.put_goto(argtuple_error_label)
3398                 code.putln('}')
3399
3400         code.putln('}') # end of the conditional unpacking blocks
3401
3402         # Convert arg values to their final type and assign them.
3403         # Also inject non-Python default arguments, which do cannot
3404         # live in the values[] array.
3405         for i, arg in enumerate(all_args):
3406             self.generate_arg_assignment(arg, "values[%d]" % i, code)
3407
3408         code.putln('}') # end of the whole argument unpacking block
3409
3410         if code.label_used(argtuple_error_label):
3411             code.put_goto(success_label)
3412             code.put_label(argtuple_error_label)
3413             code.globalstate.use_utility_code(
3414                 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3415             code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
3416                     self.name, has_fixed_positional_count,
3417                     min_positional_args, max_positional_args,
3418                     Naming.args_cname))
3419             code.putln(code.error_goto(self.pos))
3420
3421     def generate_arg_assignment(self, arg, item, code):
3422         if arg.type.is_pyobject:
3423             # Python default arguments were already stored in 'item' at the very beginning
3424             if arg.is_generic:
3425                 item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
3426             entry = arg.entry
3427             code.putln("%s = %s;" % (entry.cname, item))
3428         else:
3429             func = arg.type.from_py_function
3430             if func:
3431                 if arg.default:
3432                     # C-typed default arguments must be handled here
3433                     code.putln('if (%s) {' % item)
3434                 rhs = "%s(%s)" % (func, item)
3435                 if arg.type.is_enum:
3436                     rhs = arg.type.cast_code(rhs)
3437                 code.putln("%s = %s; %s" % (
3438                     arg.entry.cname,
3439                     rhs,
3440                     code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
3441                 if arg.default:
3442                     code.putln('} else {')
3443                     code.putln(
3444                         "%s = %s;" % (
3445                             arg.entry.cname,
3446                             arg.calculate_default_value_code(code)))
3447                     if arg.type.is_memoryviewslice:
3448                         code.put_incref_memoryviewslice(arg.entry.cname,
3449                                                         have_gil=True)
3450                     code.putln('}')
3451             else:
3452                 error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
3453
3454     def generate_stararg_init_code(self, max_positional_args, code):
3455         if self.starstar_arg:
3456             self.starstar_arg.entry.xdecref_cleanup = 0
3457             code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % (
3458                     self.starstar_arg.entry.cname,
3459                     self.starstar_arg.entry.cname,
3460                     self.error_value()))
3461             code.put_gotref(self.starstar_arg.entry.cname)
3462         if self.star_arg:
3463             self.star_arg.entry.xdecref_cleanup = 0
3464             code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
3465                     Naming.args_cname,
3466                     max_positional_args))
3467             code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % (
3468                     self.star_arg.entry.cname, Naming.args_cname,
3469                     max_positional_args, Naming.args_cname))
3470             code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
3471             if self.starstar_arg:
3472                 code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
3473             code.put_finish_refcount_context()
3474             code.putln('return %s;' % self.error_value())
3475             code.putln('}')
3476             code.put_gotref(self.star_arg.entry.cname)
3477             code.putln('} else {')
3478             code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
3479             code.put_incref(Naming.empty_tuple, py_object_type)
3480             code.putln('}')
3481
3482     def generate_argument_values_setup_code(self, args, code):
3483         max_args = len(args)
3484         # the 'values' array collects borrowed references to arguments
3485         # before doing any type coercion etc.
3486         code.putln("PyObject* values[%d] = {%s};" % (
3487             max_args, ','.join('0'*max_args)))
3488
3489         if self.target.defaults_struct:
3490             code.putln('%s *%s = __Pyx_CyFunction_Defaults(%s, %s);' % (
3491                 self.target.defaults_struct, Naming.dynamic_args_cname,
3492                 self.target.defaults_struct, Naming.self_cname))
3493
3494         # assign borrowed Python default values to the values array,
3495         # so that they can be overwritten by received arguments below
3496         for i, arg in enumerate(args):
3497             if arg.default and arg.type.is_pyobject:
3498                 default_value = arg.calculate_default_value_code(code)
3499                 code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value)))
3500
3501     def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
3502                                         has_fixed_positional_count, has_kw_only_args,
3503                                         all_args, argtuple_error_label, code):
3504         code.putln('Py_ssize_t kw_args;')
3505         code.putln('const Py_ssize_t pos_args = PyTuple_GET_SIZE(%s);' % Naming.args_cname)
3506         # copy the values from the args tuple and check that it's not too long
3507         code.putln('switch (pos_args) {')
3508         if self.star_arg:
3509             code.putln('default:')
3510         for i in range(max_positional_args-1, -1, -1):
3511             code.put('case %2d: ' % (i+1))
3512             code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
3513                     i, Naming.args_cname, i))
3514         code.putln('case  0: break;')
3515         if not self.star_arg:
3516             code.put('default: ') # more arguments than allowed
3517             code.put_goto(argtuple_error_label)
3518         code.putln('}')
3519
3520         # The code above is very often (but not always) the same as
3521         # the optimised non-kwargs tuple unpacking code, so we keep
3522         # the code block above at the very top, before the following
3523         # 'external' PyDict_Size() call, to make it easy for the C
3524         # compiler to merge the two separate tuple unpacking
3525         # implementations into one when they turn out to be identical.
3526
3527         # If we received kwargs, fill up the positional/required
3528         # arguments with values from the kw dict
3529         code.putln('kw_args = PyDict_Size(%s);' % Naming.kwds_cname)
3530         if self.num_required_args or max_positional_args > 0:
3531             last_required_arg = -1
3532             for i, arg in enumerate(all_args):
3533                 if not arg.default:
3534                     last_required_arg = i
3535             if last_required_arg < max_positional_args:
3536                 last_required_arg = max_positional_args-1
3537             if max_positional_args > 0:
3538                 code.putln('switch (pos_args) {')
3539             for i, arg in enumerate(all_args[:last_required_arg+1]):
3540                 if max_positional_args > 0 and i <= max_positional_args:
3541                     if self.star_arg and i == max_positional_args:
3542                         code.putln('default:')
3543                     else:
3544                         code.putln('case %2d:' % i)
3545                 pystring_cname = code.intern_identifier(arg.name)
3546                 if arg.default:
3547                     if arg.kw_only:
3548                         # optional kw-only args are handled separately below
3549                         continue
3550                     code.putln('if (kw_args > 0) {')
3551                     # don't overwrite default argument
3552                     code.putln('PyObject* value = PyDict_GetItem(%s, %s);' % (
3553                         Naming.kwds_cname, pystring_cname))
3554                     code.putln('if (value) { values[%d] = value; kw_args--; }' % i)
3555                     code.putln('}')
3556                 else:
3557                     code.putln('if (likely((values[%d] = PyDict_GetItem(%s, %s)) != 0)) kw_args--;' % (
3558                         i, Naming.kwds_cname, pystring_cname))
3559                     if i < min_positional_args:
3560                         if i == 0:
3561                             # special case: we know arg 0 is missing
3562                             code.put('else ')
3563                             code.put_goto(argtuple_error_label)
3564                         else:
3565                             # print the correct number of values (args or
3566                             # kwargs) that were passed into positional
3567                             # arguments up to this point
3568                             code.putln('else {')
3569                             code.globalstate.use_utility_code(
3570                                 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3571                             code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
3572                                     self.name, has_fixed_positional_count,
3573                                     min_positional_args, max_positional_args, i))
3574                             code.putln(code.error_goto(self.pos))
3575                             code.putln('}')
3576                     elif arg.kw_only:
3577                         code.putln('else {')
3578                         code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
3579                                 self.name, pystring_cname))
3580                         code.putln(code.error_goto(self.pos))
3581                         code.putln('}')
3582             if max_positional_args > 0:
3583                 code.putln('}')
3584
3585         if has_kw_only_args:
3586             # unpack optional keyword-only arguments separately because
3587             # checking for interned strings in a dict is faster than iterating
3588             self.generate_optional_kwonly_args_unpacking_code(all_args, code)
3589
3590         code.putln('if (unlikely(kw_args > 0)) {')
3591         # non-positional/-required kw args left in dict: default args,
3592         # kw-only args, **kwargs or error
3593         #
3594         # This is sort of a catch-all: except for checking required
3595         # arguments, this will always do the right thing for unpacking
3596         # keyword arguments, so that we can concentrate on optimising
3597         # common cases above.
3598         if max_positional_args == 0:
3599             pos_arg_count = "0"
3600         elif self.star_arg:
3601             code.putln("const Py_ssize_t used_pos_args = (pos_args < %d) ? pos_args : %d;" % (
3602                     max_positional_args, max_positional_args))
3603             pos_arg_count = "used_pos_args"
3604         else:
3605             pos_arg_count = "pos_args"
3606         code.globalstate.use_utility_code(
3607             UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c"))
3608         code.putln(
3609             'if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % (
3610                 Naming.kwds_cname,
3611                 Naming.pykwdlist_cname,
3612                 self.starstar_arg and self.starstar_arg.entry.cname or '0',
3613                 pos_arg_count,
3614                 self.name,
3615                 code.error_goto(self.pos)))
3616         code.putln('}')
3617
3618     def generate_optional_kwonly_args_unpacking_code(self, all_args, code):
3619         optional_args = []
3620         first_optional_arg = -1
3621         for i, arg in enumerate(all_args):
3622             if not arg.kw_only or not arg.default:
3623                 continue
3624             if not optional_args:
3625                 first_optional_arg = i
3626             optional_args.append(arg.name)
3627         if optional_args:
3628             if len(optional_args) > 1:
3629                 # if we receive more than the named kwargs, we either have **kwargs
3630                 # (in which case we must iterate anyway) or it's an error (which we
3631                 # also handle during iteration) => skip this part if there are more
3632                 code.putln('if (kw_args > 0 && %s(kw_args <= %d)) {' % (
3633                     not self.starstar_arg and 'likely' or '',
3634                     len(optional_args)))
3635                 code.putln('Py_ssize_t index;')
3636                 # not unrolling the loop here reduces the C code overhead
3637                 code.putln('for (index = %d; index < %d && kw_args > 0; index++) {' % (
3638                     first_optional_arg, first_optional_arg + len(optional_args)))
3639             else:
3640                 code.putln('if (kw_args == 1) {')
3641                 code.putln('const Py_ssize_t index = %d;' % first_optional_arg)
3642             code.putln('PyObject* value = PyDict_GetItem(%s, *%s[index]);' % (
3643                 Naming.kwds_cname, Naming.pykwdlist_cname))
3644             code.putln('if (value) { values[index] = value; kw_args--; }')
3645             if len(optional_args) > 1:
3646                 code.putln('}')
3647             code.putln('}')
3648
3649     def generate_argument_conversion_code(self, code):
3650         # Generate code to convert arguments from signature type to
3651         # declared type, if needed.  Also copies signature arguments
3652         # into closure fields.
3653         for arg in self.args:
3654             if arg.needs_conversion:
3655                 self.generate_arg_conversion(arg, code)
3656
3657     def generate_arg_conversion(self, arg, code):
3658         # Generate conversion code for one argument.
3659         old_type = arg.hdr_type
3660         new_type = arg.type
3661         if old_type.is_pyobject:
3662             if arg.default:
3663                 code.putln("if (%s) {" % arg.hdr_cname)
3664             else:
3665                 code.putln("assert(%s); {" % arg.hdr_cname)
3666             self.generate_arg_conversion_from_pyobject(arg, code)
3667             code.putln("}")
3668         elif new_type.is_pyobject:
3669             self.generate_arg_conversion_to_pyobject(arg, code)
3670         else:
3671             if new_type.assignable_from(old_type):
3672                 code.putln(
3673                     "%s = %s;" % (arg.entry.cname, arg.hdr_cname))
3674             else:
3675                 error(arg.pos,
3676                     "Cannot convert 1 argument from '%s' to '%s'" %
3677                         (old_type, new_type))
3678
3679     def generate_arg_conversion_from_pyobject(self, arg, code):
3680         new_type = arg.type
3681         func = new_type.from_py_function
3682         # copied from CoerceFromPyTypeNode
3683         if func:
3684             lhs = arg.entry.cname
3685             rhs = "%s(%s)" % (func, arg.hdr_cname)
3686             if new_type.is_enum:
3687                 rhs = PyrexTypes.typecast(new_type, PyrexTypes.c_long_type, rhs)
3688             code.putln("%s = %s; %s" % (
3689                 lhs,
3690                 rhs,
3691                 code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
3692         else:
3693             error(arg.pos,
3694                 "Cannot convert Python object argument to type '%s'"
3695                     % new_type)
3696
3697     def generate_arg_conversion_to_pyobject(self, arg, code):
3698         old_type = arg.hdr_type
3699         func = old_type.to_py_function
3700         if func:
3701             code.putln("%s = %s(%s); %s" % (
3702                 arg.entry.cname,
3703                 func,
3704                 arg.hdr_cname,
3705                 code.error_goto_if_null(arg.entry.cname, arg.pos)))
3706             code.put_var_gotref(arg.entry)
3707         else:
3708             error(arg.pos,
3709                 "Cannot convert argument of type '%s' to Python object"
3710                     % old_type)
3711
3712     def generate_argument_type_tests(self, code):
3713         # Generate type tests for args whose signature
3714         # type is PyObject * and whose declared type is
3715         # a subtype thereof.
3716         for arg in self.args:
3717             if arg.needs_type_test:
3718                 self.generate_arg_type_test(arg, code)
3719             elif not arg.accept_none and (arg.type.is_pyobject or
3720                                           arg.type.is_buffer or
3721                                           arg.type.is_memoryviewslice):
3722                 self.generate_arg_none_check(arg, code)
3723
3724     def error_value(self):
3725         return self.signature.error_value
3726
3727
3728 class GeneratorDefNode(DefNode):
3729     # Generator function node that creates a new generator instance when called.
3730     #
3731     # gbody          GeneratorBodyDefNode   the function implementing the generator
3732     #
3733
3734     is_generator = True
3735     needs_closure = True
3736
3737     child_attrs = DefNode.child_attrs + ["gbody"]
3738
3739     def __init__(self, **kwargs):
3740         # XXX: don't actually needs a body
3741         kwargs['body'] = StatListNode(kwargs['pos'], stats=[])
3742         super(GeneratorDefNode, self).__init__(**kwargs)
3743
3744     def analyse_declarations(self, env):
3745         super(GeneratorDefNode, self).analyse_declarations(env)
3746         self.gbody.local_scope = self.local_scope
3747         self.gbody.analyse_declarations(env)
3748
3749     def generate_function_body(self, env, code):
3750         body_cname = self.gbody.entry.func_cname
3751
3752         code.putln('{')
3753         code.putln('__pyx_GeneratorObject *gen = __Pyx_Generator_New('
3754                    '(__pyx_generator_body_t) %s, (PyObject *) %s); %s' % (
3755                        body_cname, Naming.cur_scope_cname,
3756                        code.error_goto_if_null('gen', self.pos)))
3757         code.put_decref(Naming.cur_scope_cname, py_object_type)
3758         if self.requires_classobj:
3759             classobj_cname = 'gen->classobj'
3760             code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
3761                 classobj_cname, Naming.self_cname))
3762             code.put_incref(classobj_cname, py_object_type)
3763             code.put_giveref(classobj_cname)
3764         code.put_finish_refcount_context()
3765         code.putln('return (PyObject *) gen;')
3766         code.putln('}')
3767
3768     def generate_function_definitions(self, env, code):
3769         env.use_utility_code(UtilityCode.load_cached("Generator", "Generator.c"))
3770
3771         self.gbody.generate_function_header(code, proto=True)
3772         super(GeneratorDefNode, self).generate_function_definitions(env, code)
3773         self.gbody.generate_function_definitions(env, code)
3774
3775
3776 class GeneratorBodyDefNode(DefNode):
3777     # Main code body of a generator implemented as a DefNode.
3778     #
3779
3780     is_generator_body = True
3781
3782     def __init__(self, pos=None, name=None, body=None):
3783         super(GeneratorBodyDefNode, self).__init__(
3784             pos=pos, body=body, name=name, doc=None,
3785             args=[], star_arg=None, starstar_arg=None)
3786
3787     def declare_generator_body(self, env):
3788         prefix = env.next_id(env.scope_prefix)
3789         name = env.next_id('generator')
3790         cname = Naming.genbody_prefix + prefix + name
3791         entry = env.declare_var(None, py_object_type, self.pos,
3792                                 cname=cname, visibility='private')
3793         entry.func_cname = cname
3794         entry.qualified_name = EncodedString(self.name)
3795         self.entry = entry
3796
3797     def analyse_declarations(self, env):
3798         self.analyse_argument_types(env)
3799         self.declare_generator_body(env)
3800
3801     def generate_function_header(self, code, proto=False):
3802         header = "static PyObject *%s(__pyx_GeneratorObject *%s, PyObject *%s)" % (
3803             self.entry.func_cname,
3804             Naming.generator_cname,
3805             Naming.sent_value_cname)
3806         if proto:
3807             code.putln('%s; /* proto */' % header)
3808         else:
3809             code.putln('%s /* generator body */\n{' % header)
3810
3811     def generate_function_definitions(self, env, code):
3812         lenv = self.local_scope
3813
3814         # Generate closure function definitions
3815         self.body.generate_function_definitions(lenv, code)
3816
3817         # Generate C code for header and body of function
3818         code.enter_cfunc_scope()
3819         code.return_from_error_cleanup_label = code.new_label()
3820
3821         # ----- Top-level constants used by this function
3822         code.mark_pos(self.pos)
3823         self.generate_cached_builtins_decls(lenv, code)
3824         # ----- Function header
3825         code.putln("")
3826         self.generate_function_header(code)
3827         closure_init_code = code.insertion_point()
3828         # ----- Local variables
3829         code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
3830         tempvardecl_code = code.insertion_point()
3831         code.put_declare_refcount_context()
3832         code.put_setup_refcount_context(self.entry.name)
3833
3834         # ----- Resume switch point.
3835         code.funcstate.init_closure_temps(lenv.scope_class.type.scope)
3836         resume_code = code.insertion_point()
3837         first_run_label = code.new_label('first_run')
3838         code.use_label(first_run_label)
3839         code.put_label(first_run_label)
3840         code.putln('%s' %
3841                    (code.error_goto_if_null(Naming.sent_value_cname, self.pos)))
3842
3843         # ----- Function body
3844         self.generate_function_body(env, code)
3845         # ----- Closure initialization
3846         if lenv.scope_class.type.scope.entries:
3847             closure_init_code.putln('%s = %s;' % (
3848                 lenv.scope_class.type.declaration_code(Naming.cur_scope_cname),
3849                 lenv.scope_class.type.cast_code('%s->closure' %
3850                                                 Naming.generator_cname)))
3851
3852         code.mark_pos(self.pos)
3853         code.putln("")
3854         code.putln("/* function exit code */")
3855
3856         # on normal generator termination, we do not take the exception propagation
3857         # path: no traceback info is required and not creating it is much faster
3858         if not self.body.is_terminator:
3859             code.putln('PyErr_SetNone(PyExc_StopIteration);')
3860         # ----- Error cleanup
3861         if code.error_label in code.labels_used:
3862             if not self.body.is_terminator:
3863                 code.put_goto(code.return_label)
3864             code.put_label(code.error_label)
3865             for cname, type in code.funcstate.all_managed_temps():
3866                 code.put_xdecref(cname, type)
3867             code.put_add_traceback(self.entry.qualified_name)
3868
3869         # ----- Non-error return cleanup
3870         code.put_label(code.return_label)
3871         code.put_xdecref(Naming.retval_cname, py_object_type)
3872         code.putln('%s->resume_label = -1;' % Naming.generator_cname)
3873         # clean up as early as possible to help breaking any reference cycles
3874         code.putln('__Pyx_Generator_clear((PyObject*)%s);' % Naming.generator_cname)
3875         code.put_finish_refcount_context()
3876         code.putln('return NULL;')
3877         code.putln("}")
3878
3879         # ----- Go back and insert temp variable declarations
3880         tempvardecl_code.put_temp_declarations(code.funcstate)
3881         # ----- Generator resume code
3882         resume_code.putln("switch (%s->resume_label) {" % (
3883                        Naming.generator_cname))
3884         resume_code.putln("case 0: goto %s;" % first_run_label)
3885
3886         for i, label in code.yield_labels:
3887             resume_code.putln("case %d: goto %s;" % (i, label))
3888         resume_code.putln("default: /* CPython raises the right error here */")
3889         resume_code.put_finish_refcount_context()
3890         resume_code.putln("return NULL;")
3891         resume_code.putln("}")
3892
3893         code.exit_cfunc_scope()
3894
3895
3896 class OverrideCheckNode(StatNode):
3897     # A Node for dispatching to the def method if it
3898     # is overriden.
3899     #
3900     #  py_func
3901     #
3902     #  args
3903     #  func_temp
3904     #  body
3905
3906     child_attrs = ['body']
3907
3908     body = None
3909
3910     def analyse_expressions(self, env):
3911         self.args = env.arg_entries
3912         if self.py_func.is_module_scope:
3913             first_arg = 0
3914         else:
3915             first_arg = 1
3916         import ExprNodes
3917         self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
3918         call_node = ExprNodes.SimpleCallNode(
3919             self.pos, function=self.func_node,
3920             args=[ ExprNodes.NameNode(self.pos, name=arg.name)
3921                    for arg in self.args[first_arg:] ])
3922         self.body = ReturnStatNode(self.pos, value=call_node)
3923         self.body = self.body.analyse_expressions(env)
3924         return self
3925
3926     def generate_execution_code(self, code):
3927         interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
3928         # Check to see if we are an extension type
3929         if self.py_func.is_module_scope:
3930             self_arg = "((PyObject *)%s)" % Naming.module_cname
3931         else:
3932             self_arg = "((PyObject *)%s)" % self.args[0].cname
3933         code.putln("/* Check if called by wrapper */")
3934         code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
3935         code.putln("/* Check if overridden in Python */")
3936         if self.py_func.is_module_scope:
3937             code.putln("else {")
3938         else:
3939             code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
3940         func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
3941         self.func_node.set_cname(func_node_temp)
3942         # need to get attribute manually--scope would return cdef method
3943         code.globalstate.use_utility_code(
3944             UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
3945         err = code.error_goto_if_null(func_node_temp, self.pos)
3946         code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % (
3947             func_node_temp, self_arg, interned_attr_cname, err))
3948         code.put_gotref(func_node_temp)
3949         is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
3950         is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)%s)" % (
3951             func_node_temp, self.py_func.entry.func_cname)
3952         code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden))
3953         self.body.generate_execution_code(code)
3954         code.putln("}")
3955         code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
3956         code.funcstate.release_temp(func_node_temp)
3957         code.putln("}")
3958
3959 class ClassDefNode(StatNode, BlockNode):
3960     pass
3961
3962 class PyClassDefNode(ClassDefNode):
3963     #  A Python class definition.
3964     #
3965     #  name     EncodedString   Name of the class
3966     #  doc      string or None
3967     #  body     StatNode        Attribute definition code
3968     #  entry    Symtab.Entry
3969     #  scope    PyClassScope
3970     #  decorators    [DecoratorNode]        list of decorators or None
3971     #
3972     #  The following subnodes are constructed internally:
3973     #
3974     #  dict     DictNode   Class dictionary or Py3 namespace
3975     #  classobj ClassNode  Class object
3976     #  target   NameNode   Variable to assign class object to
3977
3978     child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result",
3979                    "target", "class_cell", "decorators"]
3980     decorators = None
3981     class_result = None
3982     is_py3_style_class = False  # Python3 style class (kwargs)
3983     metaclass = None
3984     mkw = None
3985
3986     def __init__(self, pos, name, bases, doc, body, decorators=None,
3987                  keyword_args=None, starstar_arg=None, force_py3_semantics=False):
3988         StatNode.__init__(self, pos)
3989         self.name = name
3990         self.doc = doc
3991         self.body = body
3992         self.decorators = decorators
3993         self.bases = bases
3994         import ExprNodes
3995         if self.doc and Options.docstrings:
3996             doc = embed_position(self.pos, self.doc)
3997             doc_node = ExprNodes.StringNode(pos, value=doc)
3998         else:
3999             doc_node = None
4000
4001         allow_py2_metaclass = not force_py3_semantics
4002         if keyword_args or starstar_arg:
4003             allow_py2_metaclass = False
4004             self.is_py3_style_class = True
4005             if keyword_args and not starstar_arg:
4006                 for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
4007                     if item.key.value == 'metaclass':
4008                         if self.metaclass is not None:
4009                             error(item.pos, "keyword argument 'metaclass' passed multiple times")
4010                         # special case: we already know the metaclass,
4011                         # so we don't need to do the "build kwargs,
4012                         # find metaclass" dance at runtime
4013                         self.metaclass = item.value
4014                         del keyword_args.key_value_pairs[i]
4015             if starstar_arg:
4016                 self.mkw = ExprNodes.KeywordArgsNode(
4017                     pos, keyword_args=keyword_args and keyword_args.key_value_pairs or [],
4018                     starstar_arg=starstar_arg)
4019             elif keyword_args.key_value_pairs:
4020                 self.mkw = keyword_args
4021             else:
4022                 assert self.metaclass is not None
4023
4024         if force_py3_semantics or self.bases or self.mkw or self.metaclass:
4025             if self.metaclass is None:
4026                 if starstar_arg:
4027                     # **kwargs may contain 'metaclass' arg
4028                     mkdict = self.mkw
4029                 else:
4030                     mkdict = None
4031                 if (not mkdict and
4032                         self.bases.is_sequence_constructor and
4033                         not self.bases.args):
4034                     pass  # no base classes => no inherited metaclass
4035                 else:
4036                     self.metaclass = ExprNodes.PyClassMetaclassNode(
4037                         pos, mkw=mkdict, bases=self.bases)
4038                 needs_metaclass_calculation = False
4039             else:
4040                 needs_metaclass_calculation = True
4041
4042             self.dict = ExprNodes.PyClassNamespaceNode(
4043                 pos, name=name, doc=doc_node,
4044                 metaclass=self.metaclass, bases=self.bases, mkw=self.mkw)
4045             self.classobj = ExprNodes.Py3ClassNode(
4046                 pos, name=name,
4047                 bases=self.bases, dict=self.dict, doc=doc_node,
4048                 metaclass=self.metaclass, mkw=self.mkw,
4049                 calculate_metaclass=needs_metaclass_calculation,
4050                 allow_py2_metaclass=allow_py2_metaclass)
4051         else:
4052             # no bases, no metaclass => old style class creation
4053             self.dict = ExprNodes.DictNode(pos, key_value_pairs=[])
4054             self.classobj = ExprNodes.ClassNode(
4055                 pos, name=name,
4056                 bases=bases, dict=self.dict, doc=doc_node)
4057
4058         self.target = ExprNodes.NameNode(pos, name=name)
4059         self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos)
4060
4061     def as_cclass(self):
4062         """
4063         Return this node as if it were declared as an extension class
4064         """
4065         if self.is_py3_style_class:
4066             error(self.classobj.pos, "Python3 style class could not be represented as C class")
4067             return
4068         bases = self.classobj.bases.args
4069         if len(bases) == 0:
4070             base_class_name = None
4071             base_class_module = None
4072         elif len(bases) == 1:
4073             base = bases[0]
4074             path = []
4075             from ExprNodes import AttributeNode, NameNode
4076             while isinstance(base, AttributeNode):
4077                 path.insert(0, base.attribute)
4078                 base = base.obj
4079             if isinstance(base, NameNode):
4080                 path.insert(0, base.name)
4081                 base_class_name = path[-1]
4082                 if len(path) > 1:
4083                     base_class_module = u'.'.join(path[:-1])
4084                 else:
4085                     base_class_module = None
4086             else:
4087                 error(self.classobj.bases.args.pos, "Invalid base class")
4088         else:
4089             error(self.classobj.bases.args.pos, "C class may only have one base class")
4090             return None
4091
4092         return CClassDefNode(self.pos,
4093                              visibility = 'private',
4094                              module_name = None,
4095                              class_name = self.name,
4096                              base_class_module = base_class_module,
4097                              base_class_name = base_class_name,
4098                              decorators = self.decorators,
4099                              body = self.body,
4100                              in_pxd = False,
4101                              doc = self.doc)
4102
4103     def create_scope(self, env):
4104         genv = env
4105         while genv.is_py_class_scope or genv.is_c_class_scope:
4106             genv = genv.outer_scope
4107         cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
4108         return cenv
4109
4110     def analyse_declarations(self, env):
4111         class_result = self.classobj
4112         if self.decorators:
4113             from ExprNodes import SimpleCallNode
4114             for decorator in self.decorators[::-1]:
4115                 class_result = SimpleCallNode(
4116                     decorator.pos,
4117                     function = decorator.decorator,
4118                     args = [class_result])
4119             self.decorators = None
4120         self.class_result = class_result
4121         self.class_result.analyse_declarations(env)
4122         self.target.analyse_target_declaration(env)
4123         cenv = self.create_scope(env)
4124         cenv.directives = env.directives
4125         cenv.class_obj_cname = self.target.entry.cname
4126         self.body.analyse_declarations(cenv)
4127
4128     def analyse_expressions(self, env):
4129         if self.bases:
4130             self.bases = self.bases.analyse_expressions(env)
4131         if self.metaclass:
4132             self.metaclass = self.metaclass.analyse_expressions(env)
4133         if self.mkw:
4134             self.mkw = self.mkw.analyse_expressions(env)
4135         self.dict = self.dict.analyse_expressions(env)
4136         self.class_result = self.class_result.analyse_expressions(env)
4137         genv = env.global_scope()
4138         cenv = self.scope
4139         self.body = self.body.analyse_expressions(cenv)
4140         self.target.analyse_target_expression(env, self.classobj)
4141         self.class_cell = self.class_cell.analyse_expressions(cenv)
4142         return self
4143
4144     def generate_function_definitions(self, env, code):
4145         self.generate_lambda_definitions(self.scope, code)
4146         self.body.generate_function_definitions(self.scope, code)
4147
4148     def generate_execution_code(self, code):
4149         code.pyclass_stack.append(self)
4150         cenv = self.scope
4151         if self.bases:
4152             self.bases.generate_evaluation_code(code)
4153         if self.mkw:
4154             self.mkw.generate_evaluation_code(code)
4155         if self.metaclass:
4156             self.metaclass.generate_evaluation_code(code)
4157         self.dict.generate_evaluation_code(code)
4158         cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
4159         self.class_cell.generate_evaluation_code(code)
4160         self.body.generate_execution_code(code)
4161         self.class_result.generate_evaluation_code(code)
4162         self.class_cell.generate_injection_code(
4163             code, self.class_result.result())
4164         self.class_cell.generate_disposal_code(code)
4165         cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
4166         self.target.generate_assignment_code(self.class_result, code)
4167         self.dict.generate_disposal_code(code)
4168         self.dict.free_temps(code)
4169         if self.metaclass:
4170             self.metaclass.generate_disposal_code(code)
4171             self.metaclass.free_temps(code)
4172         if self.mkw:
4173             self.mkw.generate_disposal_code(code)
4174             self.mkw.free_temps(code)
4175         if self.bases:
4176             self.bases.generate_disposal_code(code)
4177             self.bases.free_temps(code)
4178         code.pyclass_stack.pop()
4179
4180 class CClassDefNode(ClassDefNode):
4181     #  An extension type definition.
4182     #
4183     #  visibility         'private' or 'public' or 'extern'
4184     #  typedef_flag       boolean
4185     #  api                boolean
4186     #  module_name        string or None    For import of extern type objects
4187     #  class_name         string            Unqualified name of class
4188     #  as_name            string or None    Name to declare as in this scope
4189     #  base_class_module  string or None    Module containing the base class
4190     #  base_class_name    string or None    Name of the base class
4191     #  objstruct_name     string or None    Specified C name of object struct
4192     #  typeobj_name       string or None    Specified C name of type object
4193     #  in_pxd             boolean           Is in a .pxd file
4194     #  decorators         [DecoratorNode]   list of decorators or None
4195     #  doc                string or None
4196     #  body               StatNode or None
4197     #  entry              Symtab.Entry
4198     #  base_type          PyExtensionType or None
4199     #  buffer_defaults_node DictNode or None Declares defaults for a buffer
4200     #  buffer_defaults_pos
4201
4202     child_attrs = ["body"]
4203     buffer_defaults_node = None
4204     buffer_defaults_pos = None
4205     typedef_flag = False
4206     api = False
4207     objstruct_name = None
4208     typeobj_name = None
4209     decorators = None
4210     shadow = False
4211
4212     def buffer_defaults(self, env):
4213         if not hasattr(self, '_buffer_defaults'):
4214             import Buffer
4215             if self.buffer_defaults_node:
4216                 self._buffer_defaults = Buffer.analyse_buffer_options(
4217                     self.buffer_defaults_pos,
4218                     env, [], self.buffer_defaults_node,
4219                     need_complete=False)
4220             else:
4221                 self._buffer_defaults = None
4222         return self._buffer_defaults
4223
4224     def declare(self, env):
4225         if self.module_name and self.visibility != 'extern':
4226             module_path = self.module_name.split(".")
4227             home_scope = env.find_imported_module(module_path, self.pos)
4228             if not home_scope:
4229                 return None
4230         else:
4231             home_scope = env
4232
4233         self.entry = home_scope.declare_c_class(
4234             name = self.class_name,
4235             pos = self.pos,
4236             defining = 0,
4237             implementing = 0,
4238             module_name = self.module_name,
4239             base_type = None,
4240             objstruct_cname = self.objstruct_name,
4241             typeobj_cname = self.typeobj_name,
4242             visibility = self.visibility,
4243             typedef_flag = self.typedef_flag,
4244             api = self.api,
4245             buffer_defaults = self.buffer_defaults(env),
4246             shadow = self.shadow)
4247
4248     def analyse_declarations(self, env):
4249         #print "CClassDefNode.analyse_declarations:", self.class_name
4250         #print "...visibility =", self.visibility
4251         #print "...module_name =", self.module_name
4252
4253         if env.in_cinclude and not self.objstruct_name:
4254             error(self.pos, "Object struct name specification required for "
4255                 "C class defined in 'extern from' block")
4256         if self.decorators:
4257             error(self.pos,
4258                   "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name)
4259         self.base_type = None
4260         # Now that module imports are cached, we need to
4261         # import the modules for extern classes.
4262         if self.module_name:
4263             self.module = None
4264             for module in env.cimported_modules:
4265                 if module.name == self.module_name:
4266                     self.module = module
4267             if self.module is None:
4268                 self.module = ModuleScope(self.module_name, None, env.context)
4269                 self.module.has_extern_class = 1
4270                 env.add_imported_module(self.module)
4271
4272         if self.base_class_name:
4273             if self.base_class_module:
4274                 base_class_scope = env.find_module(self.base_class_module, self.pos)
4275             else:
4276                 base_class_scope = env
4277             if self.base_class_name == 'object':
4278                 # extension classes are special and don't need to inherit from object
4279                 if base_class_scope is None or base_class_scope.lookup('object') is None:
4280                     self.base_class_name = None
4281                     self.base_class_module = None
4282                     base_class_scope = None
4283             if base_class_scope:
4284                 base_class_entry = base_class_scope.find(self.base_class_name, self.pos)
4285                 if base_class_entry:
4286                     if not base_class_entry.is_type:
4287                         error(self.pos, "'%s' is not a type name" % self.base_class_name)
4288                     elif not base_class_entry.type.is_extension_type and \
4289                              not (base_class_entry.type.is_builtin_type and
4290                                   base_class_entry.type.objstruct_cname):
4291                         error(self.pos, "'%s' is not an extension type" % self.base_class_name)
4292                     elif not base_class_entry.type.is_complete():
4293                         error(self.pos, "Base class '%s' of type '%s' is incomplete" % (
4294                             self.base_class_name, self.class_name))
4295                     elif base_class_entry.type.scope and base_class_entry.type.scope.directives and \
4296                              base_class_entry.type.is_final_type:
4297                         error(self.pos, "Base class '%s' of type '%s' is final" % (
4298                             self.base_class_name, self.class_name))
4299                     elif base_class_entry.type.is_builtin_type and \
4300                              base_class_entry.type.name in ('tuple', 'str', 'bytes'):
4301                         error(self.pos, "inheritance from PyVarObject types like '%s' is not currently supported"
4302                               % base_class_entry.type.name)
4303                     else:
4304                         self.base_type = base_class_entry.type
4305                 if env.directives.get('freelist', 0) > 0:
4306                     warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1)
4307
4308         has_body = self.body is not None
4309         if has_body and self.base_type and not self.base_type.scope:
4310             # To properly initialize inherited attributes, the base type must
4311             # be analysed before this type.
4312             self.base_type.defered_declarations.append(lambda : self.analyse_declarations(env))
4313             return
4314
4315         if self.module_name and self.visibility != 'extern':
4316             module_path = self.module_name.split(".")
4317             home_scope = env.find_imported_module(module_path, self.pos)
4318             if not home_scope:
4319                 return
4320         else:
4321             home_scope = env
4322
4323         if self.visibility == 'extern':
4324             if (self.module_name == '__builtin__' and
4325                 self.class_name in Builtin.builtin_types and
4326                 env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython
4327                 warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1)
4328
4329         self.entry = home_scope.declare_c_class(
4330             name = self.class_name,
4331             pos = self.pos,
4332             defining = has_body and self.in_pxd,
4333             implementing = has_body and not self.in_pxd,
4334             module_name = self.module_name,
4335             base_type = self.base_type,
4336             objstruct_cname = self.objstruct_name,
4337             typeobj_cname = self.typeobj_name,
4338             visibility = self.visibility,
4339             typedef_flag = self.typedef_flag,
4340             api = self.api,
4341             buffer_defaults = self.buffer_defaults(env),
4342             shadow = self.shadow)
4343
4344         if self.shadow:
4345             home_scope.lookup(self.class_name).as_variable = self.entry
4346         if home_scope is not env and self.visibility == 'extern':
4347             env.add_imported_entry(self.class_name, self.entry, self.pos)
4348         self.scope = scope = self.entry.type.scope
4349         if scope is not None:
4350             scope.directives = env.directives
4351
4352         if self.doc and Options.docstrings:
4353             scope.doc = embed_position(self.pos, self.doc)
4354
4355         if has_body:
4356             self.body.analyse_declarations(scope)
4357             if self.in_pxd:
4358                 scope.defined = 1
4359             else:
4360                 scope.implemented = 1
4361         env.allocate_vtable_names(self.entry)
4362
4363         for thunk in self.entry.type.defered_declarations:
4364             thunk()
4365
4366     def analyse_expressions(self, env):
4367         if self.body:
4368             scope = self.entry.type.scope
4369             self.body = self.body.analyse_expressions(scope)
4370         return self
4371
4372     def generate_function_definitions(self, env, code):
4373         if self.body:
4374             self.generate_lambda_definitions(self.scope, code)
4375             self.body.generate_function_definitions(self.scope, code)
4376
4377     def generate_execution_code(self, code):
4378         # This is needed to generate evaluation code for
4379         # default values of method arguments.
4380         if self.body:
4381             self.body.generate_execution_code(code)
4382
4383     def annotate(self, code):
4384         if self.body:
4385             self.body.annotate(code)
4386
4387
4388 class PropertyNode(StatNode):
4389     #  Definition of a property in an extension type.
4390     #
4391     #  name   string
4392     #  doc    EncodedString or None    Doc string
4393     #  entry  Symtab.Entry
4394     #  body   StatListNode
4395
4396     child_attrs = ["body"]
4397
4398     def analyse_declarations(self, env):
4399         self.entry = env.declare_property(self.name, self.doc, self.pos)
4400         self.entry.scope.directives = env.directives
4401         self.body.analyse_declarations(self.entry.scope)
4402
4403     def analyse_expressions(self, env):
4404         self.body = self.body.analyse_expressions(env)
4405         return self
4406
4407     def generate_function_definitions(self, env, code):
4408         self.body.generate_function_definitions(env, code)
4409
4410     def generate_execution_code(self, code):
4411         pass
4412
4413     def annotate(self, code):
4414         self.body.annotate(code)
4415
4416
4417 class GlobalNode(StatNode):
4418     # Global variable declaration.
4419     #
4420     # names    [string]
4421
4422     child_attrs = []
4423
4424     def analyse_declarations(self, env):
4425         for name in self.names:
4426             env.declare_global(name, self.pos)
4427
4428     def analyse_expressions(self, env):
4429         return self
4430
4431     def generate_execution_code(self, code):
4432         pass
4433
4434
4435 class NonlocalNode(StatNode):
4436     # Nonlocal variable declaration via the 'nonlocal' keyword.
4437     #
4438     # names    [string]
4439
4440     child_attrs = []
4441
4442     def analyse_declarations(self, env):
4443         for name in self.names:
4444             env.declare_nonlocal(name, self.pos)
4445
4446     def analyse_expressions(self, env):
4447         return self
4448
4449     def generate_execution_code(self, code):
4450         pass
4451
4452
4453 class ExprStatNode(StatNode):
4454     #  Expression used as a statement.
4455     #
4456     #  expr   ExprNode
4457
4458     child_attrs = ["expr"]
4459
4460     def analyse_declarations(self, env):
4461         import ExprNodes
4462         if isinstance(self.expr, ExprNodes.GeneralCallNode):
4463             func = self.expr.function.as_cython_attribute()
4464             if func == u'declare':
4465                 args, kwds = self.expr.explicit_args_kwds()
4466                 if len(args):
4467                     error(self.expr.pos, "Variable names must be specified.")
4468                 for var, type_node in kwds.key_value_pairs:
4469                     type = type_node.analyse_as_type(env)
4470                     if type is None:
4471                         error(type_node.pos, "Unknown type")
4472                     else:
4473                         env.declare_var(var.value, type, var.pos, is_cdef = True)
4474                 self.__class__ = PassStatNode
4475
4476     def analyse_expressions(self, env):
4477         self.expr.result_is_used = False # hint that .result() may safely be left empty
4478         self.expr = self.expr.analyse_expressions(env)
4479         return self
4480
4481     def nogil_check(self, env):
4482         if self.expr.type.is_pyobject and self.expr.is_temp:
4483             self.gil_error()
4484
4485     gil_message = "Discarding owned Python object"
4486
4487     def generate_execution_code(self, code):
4488         self.expr.generate_evaluation_code(code)
4489         if not self.expr.is_temp and self.expr.result():
4490             code.putln("%s;" % self.expr.result())
4491         self.expr.generate_disposal_code(code)
4492         self.expr.free_temps(code)
4493
4494     def generate_function_definitions(self, env, code):
4495         self.expr.generate_function_definitions(env, code)
4496
4497     def annotate(self, code):
4498         self.expr.annotate(code)
4499
4500
4501 class AssignmentNode(StatNode):
4502     #  Abstract base class for assignment nodes.
4503     #
4504     #  The analyse_expressions and generate_execution_code
4505     #  phases of assignments are split into two sub-phases
4506     #  each, to enable all the right hand sides of a
4507     #  parallel assignment to be evaluated before assigning
4508     #  to any of the left hand sides.
4509
4510     def analyse_expressions(self, env):
4511         return self.analyse_types(env)
4512
4513 #       def analyse_expressions(self, env):
4514 #           self.analyse_expressions_1(env)
4515 #           self.analyse_expressions_2(env)
4516
4517     def generate_execution_code(self, code):
4518         self.generate_rhs_evaluation_code(code)
4519         self.generate_assignment_code(code)
4520
4521
4522 class SingleAssignmentNode(AssignmentNode):
4523     #  The simplest case:
4524     #
4525     #    a = b
4526     #
4527     #  lhs      ExprNode      Left hand side
4528     #  rhs      ExprNode      Right hand side
4529     #  first    bool          Is this guaranteed the first assignment to lhs?
4530
4531     child_attrs = ["lhs", "rhs"]
4532     first = False
4533     declaration_only = False
4534
4535     def analyse_declarations(self, env):
4536         import ExprNodes
4537
4538         # handle declarations of the form x = cython.foo()
4539         if isinstance(self.rhs, ExprNodes.CallNode):
4540             func_name = self.rhs.function.as_cython_attribute()
4541             if func_name:
4542                 args, kwds = self.rhs.explicit_args_kwds()
4543
4544                 if func_name in ['declare', 'typedef']:
4545                     if len(args) > 2 or kwds is not None:
4546                         error(self.rhs.pos, "Can only declare one type at a time.")
4547                         return
4548
4549                     type = args[0].analyse_as_type(env)
4550                     if type is None:
4551                         error(args[0].pos, "Unknown type")
4552                         return
4553                     lhs = self.lhs
4554                     if func_name == 'declare':
4555                         if isinstance(lhs, ExprNodes.NameNode):
4556                             vars = [(lhs.name, lhs.pos)]
4557                         elif isinstance(lhs, ExprNodes.TupleNode):
4558                             vars = [(var.name, var.pos) for var in lhs.args]
4559                         else:
4560                             error(lhs.pos, "Invalid declaration")
4561                             return
4562                         for var, pos in vars:
4563                             env.declare_var(var, type, pos, is_cdef = True)
4564                         if len(args) == 2:
4565                             # we have a value
4566                             self.rhs = args[1]
4567                         else:
4568                             self.declaration_only = True
4569                     else:
4570                         self.declaration_only = True
4571                         if not isinstance(lhs, ExprNodes.NameNode):
4572                             error(lhs.pos, "Invalid declaration.")
4573                         env.declare_typedef(lhs.name, type, self.pos, visibility='private')
4574
4575                 elif func_name in ['struct', 'union']:
4576                     self.declaration_only = True
4577                     if len(args) > 0 or kwds is None:
4578                         error(self.rhs.pos, "Struct or union members must be given by name.")
4579                         return
4580                     members = []
4581                     for member, type_node in kwds.key_value_pairs:
4582                         type = type_node.analyse_as_type(env)
4583                         if type is None:
4584                             error(type_node.pos, "Unknown type")
4585                         else:
4586                             members.append((member.value, type, member.pos))
4587                     if len(members) < len(kwds.key_value_pairs):
4588                         return
4589                     if not isinstance(self.lhs, ExprNodes.NameNode):
4590                         error(self.lhs.pos, "Invalid declaration.")
4591                     name = self.lhs.name
4592                     scope = StructOrUnionScope(name)
4593                     env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
4594                     for member, type, pos in members:
4595                         scope.declare_var(member, type, pos)
4596
4597                 elif func_name == 'fused_type':
4598                     # dtype = cython.fused_type(...)
4599                     self.declaration_only = True
4600                     if kwds:
4601                         error(self.rhs.function.pos,
4602                               "fused_type does not take keyword arguments")
4603
4604                     fusednode = FusedTypeNode(self.rhs.pos,
4605                                               name = self.lhs.name, types=args)
4606                     fusednode.analyse_declarations(env)
4607
4608         if self.declaration_only:
4609             return
4610         else:
4611             self.lhs.analyse_target_declaration(env)
4612
4613     def analyse_types(self, env, use_temp = 0):
4614         import ExprNodes
4615
4616         self.rhs = self.rhs.analyse_types(env)
4617         self.lhs = self.lhs.analyse_target_types(env)
4618         self.lhs.gil_assignment_check(env)
4619
4620         if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast:
4621             self.lhs.memslice_broadcast = True
4622             self.rhs.memslice_broadcast = True
4623
4624         is_index_node = isinstance(self.lhs, ExprNodes.IndexNode)
4625         if (is_index_node and not self.rhs.type.is_memoryviewslice and
4626             (self.lhs.memslice_slice or self.lhs.is_memslice_copy) and
4627             (self.lhs.type.dtype.assignable_from(self.rhs.type) or
4628              self.rhs.type.is_pyobject)):
4629             # scalar slice assignment
4630             self.lhs.is_memslice_scalar_assignment = True
4631             dtype = self.lhs.type.dtype
4632         else:
4633             dtype = self.lhs.type
4634
4635         rhs = self.rhs.coerce_to(dtype, env)
4636         if use_temp or rhs.is_attribute or (
4637                 not rhs.is_name and not rhs.is_literal and
4638                 rhs.type.is_pyobject):
4639             # things like (cdef) attribute access are not safe (traverses pointers)
4640             rhs = rhs.coerce_to_temp(env)
4641         elif rhs.type.is_pyobject:
4642             rhs = rhs.coerce_to_simple(env)
4643         self.rhs = rhs
4644         return self
4645
4646     def generate_rhs_evaluation_code(self, code):
4647         self.rhs.generate_evaluation_code(code)
4648
4649     def generate_assignment_code(self, code):
4650         self.lhs.generate_assignment_code(self.rhs, code)
4651
4652     def generate_function_definitions(self, env, code):
4653         self.rhs.generate_function_definitions(env, code)
4654
4655     def annotate(self, code):
4656         self.lhs.annotate(code)
4657         self.rhs.annotate(code)
4658
4659
4660 class CascadedAssignmentNode(AssignmentNode):
4661     #  An assignment with multiple left hand sides:
4662     #
4663     #    a = b = c
4664     #
4665     #  lhs_list   [ExprNode]   Left hand sides
4666     #  rhs        ExprNode     Right hand sides
4667     #
4668     #  Used internally:
4669     #
4670     #  coerced_rhs_list   [ExprNode]   RHS coerced to type of each LHS
4671
4672     child_attrs = ["lhs_list", "rhs", "coerced_rhs_list"]
4673     coerced_rhs_list = None
4674
4675     def analyse_declarations(self, env):
4676         for lhs in self.lhs_list:
4677             lhs.analyse_target_declaration(env)
4678
4679     def analyse_types(self, env, use_temp = 0):
4680         from ExprNodes import CloneNode, ProxyNode
4681
4682         rhs = self.rhs.analyse_types(env)
4683         if use_temp or rhs.is_attribute or (
4684                 not rhs.is_name and not rhs.is_literal and
4685                 rhs.type.is_pyobject):
4686             rhs = rhs.coerce_to_temp(env)
4687         else:
4688             rhs = rhs.coerce_to_simple(env)
4689         self.rhs = ProxyNode(rhs)
4690
4691         self.coerced_rhs_list = []
4692         for lhs in self.lhs_list:
4693             lhs.analyse_target_types(env)
4694             lhs.gil_assignment_check(env)
4695             rhs = CloneNode(self.rhs)
4696             rhs = rhs.coerce_to(lhs.type, env)
4697             self.coerced_rhs_list.append(rhs)
4698         return self
4699
4700     def generate_rhs_evaluation_code(self, code):
4701         self.rhs.generate_evaluation_code(code)
4702
4703     def generate_assignment_code(self, code):
4704         for i in range(len(self.lhs_list)):
4705             lhs = self.lhs_list[i]
4706             rhs = self.coerced_rhs_list[i]
4707             rhs.generate_evaluation_code(code)
4708             lhs.generate_assignment_code(rhs, code)
4709             # Assignment has disposed of the cloned RHS
4710         self.rhs.generate_disposal_code(code)
4711         self.rhs.free_temps(code)
4712
4713     def generate_function_definitions(self, env, code):
4714         self.rhs.generate_function_definitions(env, code)
4715
4716     def annotate(self, code):
4717         for i in range(len(self.lhs_list)):
4718             self.lhs_list[i].annotate(code)
4719             self.coerced_rhs_list[i].annotate(code)
4720         self.rhs.annotate(code)
4721
4722
4723 class ParallelAssignmentNode(AssignmentNode):
4724     #  A combined packing/unpacking assignment:
4725     #
4726     #    a, b, c =  d, e, f
4727     #
4728     #  This has been rearranged by the parser into
4729     #
4730     #    a = d ; b = e ; c = f
4731     #
4732     #  but we must evaluate all the right hand sides
4733     #  before assigning to any of the left hand sides.
4734     #
4735     #  stats     [AssignmentNode]   The constituent assignments
4736
4737     child_attrs = ["stats"]
4738
4739     def analyse_declarations(self, env):
4740         for stat in self.stats:
4741             stat.analyse_declarations(env)
4742
4743     def analyse_expressions(self, env):
4744         self.stats = [ stat.analyse_types(env, use_temp = 1)
4745                        for stat in self.stats ]
4746         return self
4747
4748 #    def analyse_expressions(self, env):
4749 #        for stat in self.stats:
4750 #            stat.analyse_expressions_1(env, use_temp = 1)
4751 #        for stat in self.stats:
4752 #            stat.analyse_expressions_2(env)
4753
4754     def generate_execution_code(self, code):
4755         for stat in self.stats:
4756             stat.generate_rhs_evaluation_code(code)
4757         for stat in self.stats:
4758             stat.generate_assignment_code(code)
4759
4760     def generate_function_definitions(self, env, code):
4761         for stat in self.stats:
4762             stat.generate_function_definitions(env, code)
4763
4764     def annotate(self, code):
4765         for stat in self.stats:
4766             stat.annotate(code)
4767
4768
4769 class InPlaceAssignmentNode(AssignmentNode):
4770     #  An in place arithmetic operand:
4771     #
4772     #    a += b
4773     #    a -= b
4774     #    ...
4775     #
4776     #  lhs      ExprNode      Left hand side
4777     #  rhs      ExprNode      Right hand side
4778     #  operator char          one of "+-*/%^&|"
4779     #
4780     #  This code is a bit tricky because in order to obey Python
4781     #  semantics the sub-expressions (e.g. indices) of the lhs must
4782     #  not be evaluated twice. So we must re-use the values calculated
4783     #  in evaluation phase for the assignment phase as well.
4784     #  Fortunately, the type of the lhs node is fairly constrained
4785     #  (it must be a NameNode, AttributeNode, or IndexNode).
4786
4787     child_attrs = ["lhs", "rhs"]
4788
4789     def analyse_declarations(self, env):
4790         self.lhs.analyse_target_declaration(env)
4791
4792     def analyse_types(self, env):
4793         self.rhs = self.rhs.analyse_types(env)
4794         self.lhs = self.lhs.analyse_target_types(env)
4795
4796         # When assigning to a fully indexed buffer or memoryview, coerce the rhs
4797         if (self.lhs.is_subscript and
4798                 (self.lhs.memslice_index or self.lhs.is_buffer_access)):
4799             self.rhs = self.rhs.coerce_to(self.lhs.type, env)
4800         elif self.lhs.type.is_string and self.operator in '+-':
4801             # use pointer arithmetic for char* LHS instead of string concat
4802             self.rhs = self.rhs.coerce_to(PyrexTypes.c_py_ssize_t_type, env)
4803         return self
4804
4805     def generate_execution_code(self, code):
4806         self.rhs.generate_evaluation_code(code)
4807         self.lhs.generate_subexpr_evaluation_code(code)
4808         c_op = self.operator
4809         if c_op == "//":
4810             c_op = "/"
4811         elif c_op == "**":
4812             error(self.pos, "No C inplace power operator")
4813         if self.lhs.is_subscript and self.lhs.is_buffer_access:
4814             if self.lhs.type.is_pyobject:
4815                 error(self.pos, "In-place operators not allowed on object buffers in this release.")
4816             if (c_op in ('/', '%') and self.lhs.type.is_int
4817                 and not code.globalstate.directives['cdivision']):
4818                 error(self.pos, "In-place non-c divide operators not allowed on int buffers.")
4819             self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
4820         else:
4821             # C++
4822             # TODO: make sure overload is declared
4823             code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()))
4824         self.lhs.generate_subexpr_disposal_code(code)
4825         self.lhs.free_subexpr_temps(code)
4826         self.rhs.generate_disposal_code(code)
4827         self.rhs.free_temps(code)
4828
4829     def annotate(self, code):
4830         self.lhs.annotate(code)
4831         self.rhs.annotate(code)
4832
4833     def create_binop_node(self):
4834         import ExprNodes
4835         return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs)
4836
4837
4838 class PrintStatNode(StatNode):
4839     #  print statement
4840     #
4841     #  arg_tuple         TupleNode
4842     #  stream            ExprNode or None (stdout)
4843     #  append_newline    boolean
4844
4845     child_attrs = ["arg_tuple", "stream"]
4846
4847     def analyse_expressions(self, env):
4848         if self.stream:
4849             stream = self.stream.analyse_expressions(env)
4850             self.stream = stream.coerce_to_pyobject(env)
4851         arg_tuple = self.arg_tuple.analyse_expressions(env)
4852         self.arg_tuple = arg_tuple.coerce_to_pyobject(env)
4853         env.use_utility_code(printing_utility_code)
4854         if len(self.arg_tuple.args) == 1 and self.append_newline:
4855             env.use_utility_code(printing_one_utility_code)
4856         return self
4857
4858     nogil_check = Node.gil_error
4859     gil_message = "Python print statement"
4860
4861     def generate_execution_code(self, code):
4862         if self.stream:
4863             self.stream.generate_evaluation_code(code)
4864             stream_result = self.stream.py_result()
4865         else:
4866             stream_result = '0'
4867         if len(self.arg_tuple.args) == 1 and self.append_newline:
4868             arg = self.arg_tuple.args[0]
4869             arg.generate_evaluation_code(code)
4870
4871             code.putln(
4872                 "if (__Pyx_PrintOne(%s, %s) < 0) %s" % (
4873                     stream_result,
4874                     arg.py_result(),
4875                     code.error_goto(self.pos)))
4876             arg.generate_disposal_code(code)
4877             arg.free_temps(code)
4878         else:
4879             self.arg_tuple.generate_evaluation_code(code)
4880             code.putln(
4881                 "if (__Pyx_Print(%s, %s, %d) < 0) %s" % (
4882                     stream_result,
4883                     self.arg_tuple.py_result(),
4884                     self.append_newline,
4885                     code.error_goto(self.pos)))
4886             self.arg_tuple.generate_disposal_code(code)
4887             self.arg_tuple.free_temps(code)
4888
4889         if self.stream:
4890             self.stream.generate_disposal_code(code)
4891             self.stream.free_temps(code)
4892
4893     def generate_function_definitions(self, env, code):
4894         if self.stream:
4895             self.stream.generate_function_definitions(env, code)
4896         self.arg_tuple.generate_function_definitions(env, code)
4897
4898     def annotate(self, code):
4899         if self.stream:
4900             self.stream.annotate(code)
4901         self.arg_tuple.annotate(code)
4902
4903
4904 class ExecStatNode(StatNode):
4905     #  exec statement
4906     #
4907     #  args     [ExprNode]
4908
4909     child_attrs = ["args"]
4910
4911     def analyse_expressions(self, env):
4912         for i, arg in enumerate(self.args):
4913             arg = arg.analyse_expressions(env)
4914             arg = arg.coerce_to_pyobject(env)
4915             self.args[i] = arg
4916         env.use_utility_code(Builtin.pyexec_utility_code)
4917         return self
4918
4919     nogil_check = Node.gil_error
4920     gil_message = "Python exec statement"
4921
4922     def generate_execution_code(self, code):
4923         args = []
4924         for arg in self.args:
4925             arg.generate_evaluation_code(code)
4926             args.append( arg.py_result() )
4927         args = tuple(args + ['0', '0'][:3-len(args)])
4928         temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
4929         code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % (
4930                 (temp_result,) + args))
4931         for arg in self.args:
4932             arg.generate_disposal_code(code)
4933             arg.free_temps(code)
4934         code.putln(
4935             code.error_goto_if_null(temp_result, self.pos))
4936         code.put_gotref(temp_result)
4937         code.put_decref_clear(temp_result, py_object_type)
4938         code.funcstate.release_temp(temp_result)
4939
4940     def annotate(self, code):
4941         for arg in self.args:
4942             arg.annotate(code)
4943
4944
4945 class DelStatNode(StatNode):
4946     #  del statement
4947     #
4948     #  args     [ExprNode]
4949
4950     child_attrs = ["args"]
4951     ignore_nonexisting = False
4952
4953     def analyse_declarations(self, env):
4954         for arg in self.args:
4955             arg.analyse_target_declaration(env)
4956
4957     def analyse_expressions(self, env):
4958         for i, arg in enumerate(self.args):
4959             arg = self.args[i] = arg.analyse_target_expression(env, None)
4960             if arg.type.is_pyobject or (arg.is_name and
4961                                         arg.type.is_memoryviewslice):
4962                 if arg.is_name and arg.entry.is_cglobal:
4963                     error(arg.pos, "Deletion of global C variable")
4964             elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
4965                 self.cpp_check(env)
4966             elif arg.type.is_cpp_class:
4967                 error(arg.pos, "Deletion of non-heap C++ object")
4968             elif arg.is_subscript and arg.base.type is Builtin.bytearray_type:
4969                 pass  # del ba[i]
4970             else:
4971                 error(arg.pos, "Deletion of non-Python, non-C++ object")
4972             #arg.release_target_temp(env)
4973         return self
4974
4975     def nogil_check(self, env):
4976         for arg in self.args:
4977             if arg.type.is_pyobject:
4978                 self.gil_error()
4979
4980     gil_message = "Deleting Python object"
4981
4982     def generate_execution_code(self, code):
4983         for arg in self.args:
4984             if (arg.type.is_pyobject or
4985                     arg.type.is_memoryviewslice or
4986                     arg.is_subscript and arg.base.type is Builtin.bytearray_type):
4987                 arg.generate_deletion_code(
4988                     code, ignore_nonexisting=self.ignore_nonexisting)
4989             elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
4990                 arg.generate_result_code(code)
4991                 code.putln("delete %s;" % arg.result())
4992             # else error reported earlier
4993
4994     def annotate(self, code):
4995         for arg in self.args:
4996             arg.annotate(code)
4997
4998
4999 class PassStatNode(StatNode):
5000     #  pass statement
5001
5002     child_attrs = []
5003
5004     def analyse_expressions(self, env):
5005         return self
5006
5007     def generate_execution_code(self, code):
5008         pass
5009
5010
5011 class IndirectionNode(StatListNode):
5012     """
5013     This adds an indirection so that the node can be shared and a subtree can
5014     be removed at any time by clearing self.stats.
5015     """
5016
5017     def __init__(self, stats):
5018         super(IndirectionNode, self).__init__(stats[0].pos, stats=stats)
5019
5020 class BreakStatNode(StatNode):
5021
5022     child_attrs = []
5023     is_terminator = True
5024
5025     def analyse_expressions(self, env):
5026         return self
5027
5028     def generate_execution_code(self, code):
5029         if not code.break_label:
5030             error(self.pos, "break statement not inside loop")
5031         else:
5032             code.put_goto(code.break_label)
5033
5034
5035 class ContinueStatNode(StatNode):
5036
5037     child_attrs = []
5038     is_terminator = True
5039
5040     def analyse_expressions(self, env):
5041         return self
5042
5043     def generate_execution_code(self, code):
5044         if code.funcstate.in_try_finally:
5045             error(self.pos, "continue statement inside try of try...finally")
5046         elif not code.continue_label:
5047             error(self.pos, "continue statement not inside loop")
5048         else:
5049             code.put_goto(code.continue_label)
5050
5051
5052 class ReturnStatNode(StatNode):
5053     #  return statement
5054     #
5055     #  value         ExprNode or None
5056     #  return_type   PyrexType
5057     #  in_generator  return inside of generator => raise StopIteration
5058
5059     child_attrs = ["value"]
5060     is_terminator = True
5061     in_generator = False
5062
5063     # Whether we are in a parallel section
5064     in_parallel = False
5065
5066     def analyse_expressions(self, env):
5067         return_type = env.return_type
5068         self.return_type = return_type
5069         if not return_type:
5070             error(self.pos, "Return not inside a function body")
5071             return self
5072         if self.value:
5073             self.value = self.value.analyse_types(env)
5074             if return_type.is_void or return_type.is_returncode:
5075                 error(self.value.pos,
5076                     "Return with value in void function")
5077             else:
5078                 self.value = self.value.coerce_to(env.return_type, env)
5079         else:
5080             if (not return_type.is_void
5081                 and not return_type.is_pyobject
5082                 and not return_type.is_returncode):
5083                     error(self.pos, "Return value required")
5084         return self
5085
5086     def nogil_check(self, env):
5087         if self.return_type.is_pyobject:
5088             self.gil_error()
5089
5090     gil_message = "Returning Python object"
5091
5092     def generate_execution_code(self, code):
5093         code.mark_pos(self.pos)
5094         if not self.return_type:
5095             # error reported earlier
5096             return
5097         if self.return_type.is_pyobject:
5098             code.put_xdecref(Naming.retval_cname,
5099                              self.return_type)
5100
5101         if self.value:
5102             self.value.generate_evaluation_code(code)
5103             if self.return_type.is_memoryviewslice:
5104                 import MemoryView
5105                 MemoryView.put_acquire_memoryviewslice(
5106                         lhs_cname=Naming.retval_cname,
5107                         lhs_type=self.return_type,
5108                         lhs_pos=self.value.pos,
5109                         rhs=self.value,
5110                         code=code,
5111                         have_gil=self.in_nogil_context)
5112             elif self.in_generator:
5113                 # return value == raise StopIteration(value), but uncatchable
5114                 code.putln(
5115                     "%s = NULL; PyErr_SetObject(PyExc_StopIteration, %s);" % (
5116                         Naming.retval_cname,
5117                         self.value.result_as(self.return_type)))
5118                 self.value.generate_disposal_code(code)
5119             else:
5120                 self.value.make_owned_reference(code)
5121                 code.putln(
5122                     "%s = %s;" % (
5123                         Naming.retval_cname,
5124                         self.value.result_as(self.return_type)))
5125             self.value.generate_post_assignment_code(code)
5126             self.value.free_temps(code)
5127         else:
5128             if self.return_type.is_pyobject:
5129                 code.put_init_to_py_none(Naming.retval_cname, self.return_type)
5130             elif self.return_type.is_returncode:
5131                 self.put_return(code, self.return_type.default_value)
5132
5133         for cname, type in code.funcstate.temps_holding_reference():
5134             code.put_decref_clear(cname, type)
5135
5136         code.put_goto(code.return_label)
5137
5138     def put_return(self, code, value):
5139         if self.in_parallel:
5140             code.putln_openmp("#pragma omp critical(__pyx_returning)")
5141         code.putln("%s = %s;" % (Naming.retval_cname, value))
5142
5143     def generate_function_definitions(self, env, code):
5144         if self.value is not None:
5145             self.value.generate_function_definitions(env, code)
5146
5147     def annotate(self, code):
5148         if self.value:
5149             self.value.annotate(code)
5150
5151
5152 class RaiseStatNode(StatNode):
5153     #  raise statement
5154     #
5155     #  exc_type    ExprNode or None
5156     #  exc_value   ExprNode or None
5157     #  exc_tb      ExprNode or None
5158     #  cause       ExprNode or None
5159
5160     child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"]
5161     is_terminator = True
5162
5163     def analyse_expressions(self, env):
5164         if self.exc_type:
5165             exc_type = self.exc_type.analyse_types(env)
5166             self.exc_type = exc_type.coerce_to_pyobject(env)
5167         if self.exc_value:
5168             exc_value = self.exc_value.analyse_types(env)
5169             self.exc_value = exc_value.coerce_to_pyobject(env)
5170         if self.exc_tb:
5171             exc_tb = self.exc_tb.analyse_types(env)
5172             self.exc_tb = exc_tb.coerce_to_pyobject(env)
5173         if self.cause:
5174             cause = self.cause.analyse_types(env)
5175             self.cause = cause.coerce_to_pyobject(env)
5176         # special cases for builtin exceptions
5177         self.builtin_exc_name = None
5178         if self.exc_type and not self.exc_value and not self.exc_tb:
5179             exc = self.exc_type
5180             import ExprNodes
5181             if (isinstance(exc, ExprNodes.SimpleCallNode) and
5182                 not (exc.args or (exc.arg_tuple is not None and
5183                                   exc.arg_tuple.args))):
5184                 exc = exc.function # extract the exception type
5185             if exc.is_name and exc.entry.is_builtin:
5186                 self.builtin_exc_name = exc.name
5187                 if self.builtin_exc_name == 'MemoryError':
5188                     self.exc_type = None # has a separate implementation
5189         return self
5190
5191     nogil_check = Node.gil_error
5192     gil_message = "Raising exception"
5193
5194     def generate_execution_code(self, code):
5195         if self.builtin_exc_name == 'MemoryError':
5196             code.putln('PyErr_NoMemory(); %s' % code.error_goto(self.pos))
5197             return
5198
5199         if self.exc_type:
5200             self.exc_type.generate_evaluation_code(code)
5201             type_code = self.exc_type.py_result()
5202         else:
5203             type_code = "0"
5204         if self.exc_value:
5205             self.exc_value.generate_evaluation_code(code)
5206             value_code = self.exc_value.py_result()
5207         else:
5208             value_code = "0"
5209         if self.exc_tb:
5210             self.exc_tb.generate_evaluation_code(code)
5211             tb_code = self.exc_tb.py_result()
5212         else:
5213             tb_code = "0"
5214         if self.cause:
5215             self.cause.generate_evaluation_code(code)
5216             cause_code = self.cause.py_result()
5217         else:
5218             cause_code = "0"
5219         code.globalstate.use_utility_code(raise_utility_code)
5220         code.putln(
5221             "__Pyx_Raise(%s, %s, %s, %s);" % (
5222                 type_code,
5223                 value_code,
5224                 tb_code,
5225                 cause_code))
5226         for obj in (self.exc_type, self.exc_value, self.exc_tb, self.cause):
5227             if obj:
5228                 obj.generate_disposal_code(code)
5229                 obj.free_temps(code)
5230         code.putln(
5231             code.error_goto(self.pos))
5232
5233     def generate_function_definitions(self, env, code):
5234         if self.exc_type is not None:
5235             self.exc_type.generate_function_definitions(env, code)
5236         if self.exc_value is not None:
5237             self.exc_value.generate_function_definitions(env, code)
5238         if self.exc_tb is not None:
5239             self.exc_tb.generate_function_definitions(env, code)
5240         if self.cause is not None:
5241             self.cause.generate_function_definitions(env, code)
5242
5243     def annotate(self, code):
5244         if self.exc_type:
5245             self.exc_type.annotate(code)
5246         if self.exc_value:
5247             self.exc_value.annotate(code)
5248         if self.exc_tb:
5249             self.exc_tb.annotate(code)
5250         if self.cause:
5251             self.cause.annotate(code)
5252
5253
5254 class ReraiseStatNode(StatNode):
5255
5256     child_attrs = []
5257     is_terminator = True
5258
5259     def analyse_expressions(self, env):
5260         return self
5261
5262     nogil_check = Node.gil_error
5263     gil_message = "Raising exception"
5264
5265     def generate_execution_code(self, code):
5266         vars = code.funcstate.exc_vars
5267         if vars:
5268             code.globalstate.use_utility_code(restore_exception_utility_code)
5269             code.put_giveref(vars[0])
5270             code.put_giveref(vars[1])
5271             # fresh exceptions may not have a traceback yet (-> finally!)
5272             code.put_xgiveref(vars[2])
5273             code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
5274             for varname in vars:
5275                 code.put("%s = 0; " % varname)
5276             code.putln()
5277             code.putln(code.error_goto(self.pos))
5278         else:
5279             code.globalstate.use_utility_code(
5280                 UtilityCode.load_cached("ReRaiseException", "Exceptions.c"))
5281             code.putln("__Pyx_ReraiseException(); %s" % code.error_goto(self.pos))
5282
5283 class AssertStatNode(StatNode):
5284     #  assert statement
5285     #
5286     #  cond    ExprNode
5287     #  value   ExprNode or None
5288
5289     child_attrs = ["cond", "value"]
5290
5291     def analyse_expressions(self, env):
5292         self.cond = self.cond.analyse_boolean_expression(env)
5293         if self.value:
5294             value = self.value.analyse_types(env)
5295             if value.type is Builtin.tuple_type or not value.type.is_builtin_type:
5296                 # prevent tuple values from being interpreted as argument value tuples
5297                 from ExprNodes import TupleNode
5298                 value = TupleNode(value.pos, args=[value], slow=True)
5299                 self.value = value.analyse_types(env, skip_children=True)
5300             else:
5301                 self.value = value.coerce_to_pyobject(env)
5302         return self
5303
5304     nogil_check = Node.gil_error
5305     gil_message = "Raising exception"
5306
5307     def generate_execution_code(self, code):
5308         code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS")
5309         code.putln("if (unlikely(!Py_OptimizeFlag)) {")
5310         self.cond.generate_evaluation_code(code)
5311         code.putln(
5312             "if (unlikely(!%s)) {" %
5313                 self.cond.result())
5314         if self.value:
5315             self.value.generate_evaluation_code(code)
5316             code.putln(
5317                 "PyErr_SetObject(PyExc_AssertionError, %s);" %
5318                     self.value.py_result())
5319             self.value.generate_disposal_code(code)
5320             self.value.free_temps(code)
5321         else:
5322             code.putln(
5323                 "PyErr_SetNone(PyExc_AssertionError);")
5324         code.putln(
5325                 code.error_goto(self.pos))
5326         code.putln(
5327             "}")
5328         self.cond.generate_disposal_code(code)
5329         self.cond.free_temps(code)
5330         code.putln(
5331             "}")
5332         code.putln("#endif")
5333
5334     def generate_function_definitions(self, env, code):
5335         self.cond.generate_function_definitions(env, code)
5336         if self.value is not None:
5337             self.value.generate_function_definitions(env, code)
5338
5339     def annotate(self, code):
5340         self.cond.annotate(code)
5341         if self.value:
5342             self.value.annotate(code)
5343
5344
5345 class IfStatNode(StatNode):
5346     #  if statement
5347     #
5348     #  if_clauses   [IfClauseNode]
5349     #  else_clause  StatNode or None
5350
5351     child_attrs = ["if_clauses", "else_clause"]
5352
5353     def analyse_declarations(self, env):
5354         for if_clause in self.if_clauses:
5355             if_clause.analyse_declarations(env)
5356         if self.else_clause:
5357             self.else_clause.analyse_declarations(env)
5358
5359     def analyse_expressions(self, env):
5360         self.if_clauses = [ if_clause.analyse_expressions(env)
5361                             for if_clause in self.if_clauses ]
5362         if self.else_clause:
5363             self.else_clause = self.else_clause.analyse_expressions(env)
5364         return self
5365
5366     def generate_execution_code(self, code):
5367         code.mark_pos(self.pos)
5368         end_label = code.new_label()
5369         for if_clause in self.if_clauses:
5370             if_clause.generate_execution_code(code, end_label)
5371         if self.else_clause:
5372             code.putln("/*else*/ {")
5373             self.else_clause.generate_execution_code(code)
5374             code.putln("}")
5375         code.put_label(end_label)
5376
5377     def generate_function_definitions(self, env, code):
5378         for clause in self.if_clauses:
5379             clause.generate_function_definitions(env, code)
5380         if self.else_clause is not None:
5381             self.else_clause.generate_function_definitions(env, code)
5382
5383     def annotate(self, code):
5384         for if_clause in self.if_clauses:
5385             if_clause.annotate(code)
5386         if self.else_clause:
5387             self.else_clause.annotate(code)
5388
5389
5390 class IfClauseNode(Node):
5391     #  if or elif clause in an if statement
5392     #
5393     #  condition   ExprNode
5394     #  body        StatNode
5395
5396     child_attrs = ["condition", "body"]
5397
5398     def analyse_declarations(self, env):
5399         self.body.analyse_declarations(env)
5400
5401     def analyse_expressions(self, env):
5402         self.condition = \
5403             self.condition.analyse_temp_boolean_expression(env)
5404         self.body = self.body.analyse_expressions(env)
5405         return self
5406
5407     def generate_execution_code(self, code, end_label):
5408         self.condition.generate_evaluation_code(code)
5409         code.putln(
5410             "if (%s) {" %
5411                 self.condition.result())
5412         self.condition.generate_disposal_code(code)
5413         self.condition.free_temps(code)
5414         self.body.generate_execution_code(code)
5415         if not self.body.is_terminator:
5416             code.put_goto(end_label)
5417         code.putln("}")
5418
5419     def generate_function_definitions(self, env, code):
5420         self.condition.generate_function_definitions(env, code)
5421         self.body.generate_function_definitions(env, code)
5422
5423     def annotate(self, code):
5424         self.condition.annotate(code)
5425         self.body.annotate(code)
5426
5427
5428 class SwitchCaseNode(StatNode):
5429     # Generated in the optimization of an if-elif-else node
5430     #
5431     # conditions    [ExprNode]
5432     # body          StatNode
5433
5434     child_attrs = ['conditions', 'body']
5435
5436     def generate_execution_code(self, code):
5437         for cond in self.conditions:
5438             code.mark_pos(cond.pos)
5439             cond.generate_evaluation_code(code)
5440             code.putln("case %s:" % cond.result())
5441         self.body.generate_execution_code(code)
5442         code.putln("break;")
5443
5444     def generate_function_definitions(self, env, code):
5445         for cond in self.conditions:
5446             cond.generate_function_definitions(env, code)
5447         self.body.generate_function_definitions(env, code)
5448
5449     def annotate(self, code):
5450         for cond in self.conditions:
5451             cond.annotate(code)
5452         self.body.annotate(code)
5453
5454 class SwitchStatNode(StatNode):
5455     # Generated in the optimization of an if-elif-else node
5456     #
5457     # test          ExprNode
5458     # cases         [SwitchCaseNode]
5459     # else_clause   StatNode or None
5460
5461     child_attrs = ['test', 'cases', 'else_clause']
5462
5463     def generate_execution_code(self, code):
5464         self.test.generate_evaluation_code(code)
5465         code.putln("switch (%s) {" % self.test.result())
5466         for case in self.cases:
5467             case.generate_execution_code(code)
5468         if self.else_clause is not None:
5469             code.putln("default:")
5470             self.else_clause.generate_execution_code(code)
5471             code.putln("break;")
5472         else:
5473             # Always generate a default clause to prevent C compiler warnings
5474             # about unmatched enum values (it was not the user who decided to
5475             # generate the switch statement, so shouldn't be bothered).
5476             code.putln("default: break;")
5477         code.putln("}")
5478
5479     def generate_function_definitions(self, env, code):
5480         self.test.generate_function_definitions(env, code)
5481         for case in self.cases:
5482             case.generate_function_definitions(env, code)
5483         if self.else_clause is not None:
5484             self.else_clause.generate_function_definitions(env, code)
5485
5486     def annotate(self, code):
5487         self.test.annotate(code)
5488         for case in self.cases:
5489             case.annotate(code)
5490         if self.else_clause is not None:
5491             self.else_clause.annotate(code)
5492
5493 class LoopNode(object):
5494     pass
5495
5496
5497 class WhileStatNode(LoopNode, StatNode):
5498     #  while statement
5499     #
5500     #  condition    ExprNode
5501     #  body         StatNode
5502     #  else_clause  StatNode
5503
5504     child_attrs = ["condition", "body", "else_clause"]
5505
5506     def analyse_declarations(self, env):
5507         self.body.analyse_declarations(env)
5508         if self.else_clause:
5509             self.else_clause.analyse_declarations(env)
5510
5511     def analyse_expressions(self, env):
5512         if self.condition:
5513             self.condition = self.condition.analyse_temp_boolean_expression(env)
5514         self.body = self.body.analyse_expressions(env)
5515         if self.else_clause:
5516             self.else_clause = self.else_clause.analyse_expressions(env)
5517         return self
5518
5519     def generate_execution_code(self, code):
5520         old_loop_labels = code.new_loop_labels()
5521         code.putln(
5522             "while (1) {")
5523         if self.condition:
5524             self.condition.generate_evaluation_code(code)
5525             self.condition.generate_disposal_code(code)
5526             code.putln(
5527                 "if (!%s) break;" %
5528                     self.condition.result())
5529             self.condition.free_temps(code)
5530         self.body.generate_execution_code(code)
5531         code.put_label(code.continue_label)
5532         code.putln("}")
5533         break_label = code.break_label
5534         code.set_loop_labels(old_loop_labels)
5535         if self.else_clause:
5536             code.mark_pos(self.else_clause.pos)
5537             code.putln("/*else*/ {")
5538             self.else_clause.generate_execution_code(code)
5539             code.putln("}")
5540         code.put_label(break_label)
5541
5542     def generate_function_definitions(self, env, code):
5543         if self.condition:
5544             self.condition.generate_function_definitions(env, code)
5545         self.body.generate_function_definitions(env, code)
5546         if self.else_clause is not None:
5547             self.else_clause.generate_function_definitions(env, code)
5548
5549     def annotate(self, code):
5550         if self.condition:
5551             self.condition.annotate(code)
5552         self.body.annotate(code)
5553         if self.else_clause:
5554             self.else_clause.annotate(code)
5555
5556
5557 class DictIterationNextNode(Node):
5558     # Helper node for calling PyDict_Next() inside of a WhileStatNode
5559     # and checking the dictionary size for changes.  Created in
5560     # Optimize.py.
5561     child_attrs = ['dict_obj', 'expected_size', 'pos_index_var',
5562                    'coerced_key_var', 'coerced_value_var', 'coerced_tuple_var',
5563                    'key_target', 'value_target', 'tuple_target', 'is_dict_flag']
5564
5565     coerced_key_var = key_ref = None
5566     coerced_value_var = value_ref = None
5567     coerced_tuple_var = tuple_ref = None
5568
5569     def __init__(self, dict_obj, expected_size, pos_index_var,
5570                  key_target, value_target, tuple_target, is_dict_flag):
5571         Node.__init__(
5572             self, dict_obj.pos,
5573             dict_obj = dict_obj,
5574             expected_size = expected_size,
5575             pos_index_var = pos_index_var,
5576             key_target = key_target,
5577             value_target = value_target,
5578             tuple_target = tuple_target,
5579             is_dict_flag = is_dict_flag,
5580             is_temp = True,
5581             type = PyrexTypes.c_bint_type)
5582
5583     def analyse_expressions(self, env):
5584         import ExprNodes
5585         self.dict_obj = self.dict_obj.analyse_types(env)
5586         self.expected_size = self.expected_size.analyse_types(env)
5587         if self.pos_index_var:
5588             self.pos_index_var = self.pos_index_var.analyse_types(env)
5589         if self.key_target:
5590             self.key_target = self.key_target.analyse_target_types(env)
5591             self.key_ref = ExprNodes.TempNode(self.key_target.pos, PyrexTypes.py_object_type)
5592             self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env)
5593         if self.value_target:
5594             self.value_target = self.value_target.analyse_target_types(env)
5595             self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type)
5596             self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
5597         if self.tuple_target:
5598             self.tuple_target = self.tuple_target.analyse_target_types(env)
5599             self.tuple_ref = ExprNodes.TempNode(self.tuple_target.pos, PyrexTypes.py_object_type)
5600             self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env)
5601         self.is_dict_flag = self.is_dict_flag.analyse_types(env)
5602         return self
5603
5604     def generate_function_definitions(self, env, code):
5605         self.dict_obj.generate_function_definitions(env, code)
5606
5607     def generate_execution_code(self, code):
5608         code.globalstate.use_utility_code(UtilityCode.load_cached("dict_iter", "Optimize.c"))
5609         self.dict_obj.generate_evaluation_code(code)
5610
5611         assignments = []
5612         temp_addresses = []
5613         for var, result, target in [(self.key_ref, self.coerced_key_var, self.key_target),
5614                                     (self.value_ref, self.coerced_value_var, self.value_target),
5615                                     (self.tuple_ref, self.coerced_tuple_var, self.tuple_target)]:
5616             if target is None:
5617                 addr = 'NULL'
5618             else:
5619                 assignments.append((var, result, target))
5620                 var.allocate(code)
5621                 addr = '&%s' % var.result()
5622             temp_addresses.append(addr)
5623
5624         result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
5625         code.putln("%s = __Pyx_dict_iter_next(%s, %s, &%s, %s, %s, %s, %s);" % (
5626             result_temp,
5627             self.dict_obj.py_result(),
5628             self.expected_size.result(),
5629             self.pos_index_var.result(),
5630             temp_addresses[0],
5631             temp_addresses[1],
5632             temp_addresses[2],
5633             self.is_dict_flag.result()
5634         ))
5635         code.putln("if (unlikely(%s == 0)) break;" % result_temp)
5636         code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos))
5637         code.funcstate.release_temp(result_temp)
5638
5639         # evaluate all coercions before the assignments
5640         for var, result, target in assignments:
5641             code.put_gotref(var.result())
5642         for var, result, target in assignments:
5643             result.generate_evaluation_code(code)
5644         for var, result, target in assignments:
5645             target.generate_assignment_code(result, code)
5646             var.release(code)
5647
5648 def ForStatNode(pos, **kw):
5649     if 'iterator' in kw:
5650         return ForInStatNode(pos, **kw)
5651     else:
5652         return ForFromStatNode(pos, **kw)
5653
5654 class ForInStatNode(LoopNode, StatNode):
5655     #  for statement
5656     #
5657     #  target        ExprNode
5658     #  iterator      IteratorNode
5659     #  body          StatNode
5660     #  else_clause   StatNode
5661     #  item          NextNode       used internally
5662
5663     child_attrs = ["target", "iterator", "body", "else_clause"]
5664     item = None
5665
5666     def analyse_declarations(self, env):
5667         import ExprNodes
5668         self.target.analyse_target_declaration(env)
5669         self.body.analyse_declarations(env)
5670         if self.else_clause:
5671             self.else_clause.analyse_declarations(env)
5672         self.item = ExprNodes.NextNode(self.iterator)
5673
5674     def analyse_expressions(self, env):
5675         self.target = self.target.analyse_target_types(env)
5676         self.iterator = self.iterator.analyse_expressions(env)
5677         import ExprNodes
5678         self.item = ExprNodes.NextNode(self.iterator)  # must rewrap after analysis
5679         self.item = self.item.analyse_expressions(env)
5680         if (self.iterator.type.is_ptr or self.iterator.type.is_array) and \
5681             self.target.type.assignable_from(self.iterator.type):
5682             # C array slice optimization.
5683             pass
5684         else:
5685             self.item = self.item.coerce_to(self.target.type, env)
5686         self.body = self.body.analyse_expressions(env)
5687         if self.else_clause:
5688             self.else_clause = self.else_clause.analyse_expressions(env)
5689         return self
5690
5691     def generate_execution_code(self, code):
5692         old_loop_labels = code.new_loop_labels()
5693         self.iterator.generate_evaluation_code(code)
5694         code.putln("for (;;) {")
5695         self.item.generate_evaluation_code(code)
5696         self.target.generate_assignment_code(self.item, code)
5697         self.body.generate_execution_code(code)
5698         code.put_label(code.continue_label)
5699         code.putln("}")
5700         break_label = code.break_label
5701         code.set_loop_labels(old_loop_labels)
5702
5703         if self.else_clause:
5704             # in nested loops, the 'else' block can contain a
5705             # 'continue' statement for the outer loop, but we may need
5706             # to generate cleanup code before taking that path, so we
5707             # intercept it here
5708             orig_continue_label = code.continue_label
5709             code.continue_label = code.new_label('outer_continue')
5710
5711             code.putln("/*else*/ {")
5712             self.else_clause.generate_execution_code(code)
5713             code.putln("}")
5714
5715             if code.label_used(code.continue_label):
5716                 code.put_goto(break_label)
5717                 code.put_label(code.continue_label)
5718                 self.iterator.generate_disposal_code(code)
5719                 code.put_goto(orig_continue_label)
5720             code.set_loop_labels(old_loop_labels)
5721
5722         if code.label_used(break_label):
5723             code.put_label(break_label)
5724         self.iterator.generate_disposal_code(code)
5725         self.iterator.free_temps(code)
5726
5727     def generate_function_definitions(self, env, code):
5728         self.target.generate_function_definitions(env, code)
5729         self.iterator.generate_function_definitions(env, code)
5730         self.body.generate_function_definitions(env, code)
5731         if self.else_clause is not None:
5732             self.else_clause.generate_function_definitions(env, code)
5733
5734     def annotate(self, code):
5735         self.target.annotate(code)
5736         self.iterator.annotate(code)
5737         self.body.annotate(code)
5738         if self.else_clause:
5739             self.else_clause.annotate(code)
5740         self.item.annotate(code)
5741
5742
5743 class ForFromStatNode(LoopNode, StatNode):
5744     #  for name from expr rel name rel expr
5745     #
5746     #  target        NameNode
5747     #  bound1        ExprNode
5748     #  relation1     string
5749     #  relation2     string
5750     #  bound2        ExprNode
5751     #  step          ExprNode or None
5752     #  body          StatNode
5753     #  else_clause   StatNode or None
5754     #
5755     #  Used internally:
5756     #
5757     #  from_range         bool
5758     #  is_py_target       bool
5759     #  loopvar_node       ExprNode (usually a NameNode or temp node)
5760     #  py_loopvar_node    PyTempNode or None
5761     child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
5762
5763     is_py_target = False
5764     loopvar_node = None
5765     py_loopvar_node = None
5766     from_range = False
5767
5768     gil_message = "For-loop using object bounds or target"
5769
5770     def nogil_check(self, env):
5771         for x in (self.target, self.bound1, self.bound2):
5772             if x.type.is_pyobject:
5773                 self.gil_error()
5774
5775     def analyse_declarations(self, env):
5776         self.target.analyse_target_declaration(env)
5777         self.body.analyse_declarations(env)
5778         if self.else_clause:
5779             self.else_clause.analyse_declarations(env)
5780
5781     def analyse_expressions(self, env):
5782         import ExprNodes
5783         self.target = self.target.analyse_target_types(env)
5784         self.bound1 = self.bound1.analyse_types(env)
5785         self.bound2 = self.bound2.analyse_types(env)
5786         if self.step is not None:
5787             if isinstance(self.step, ExprNodes.UnaryMinusNode):
5788                 warning(self.step.pos, "Probable infinite loop in for-from-by statement. Consider switching the directions of the relations.", 2)
5789             self.step = self.step.analyse_types(env)
5790
5791         if self.target.type.is_numeric:
5792             loop_type = self.target.type
5793         else:
5794             loop_type = PyrexTypes.c_int_type
5795             if not self.bound1.type.is_pyobject:
5796                 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
5797             if not self.bound2.type.is_pyobject:
5798                 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
5799             if self.step is not None and not self.step.type.is_pyobject:
5800                 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
5801         self.bound1 = self.bound1.coerce_to(loop_type, env)
5802         self.bound2 = self.bound2.coerce_to(loop_type, env)
5803         if not self.bound2.is_literal:
5804             self.bound2 = self.bound2.coerce_to_temp(env)
5805         if self.step is not None:
5806             self.step = self.step.coerce_to(loop_type, env)
5807             if not self.step.is_literal:
5808                 self.step = self.step.coerce_to_temp(env)
5809
5810         target_type = self.target.type
5811         if not (target_type.is_pyobject or target_type.is_numeric):
5812             error(self.target.pos,
5813                 "for-from loop variable must be c numeric type or Python object")
5814         if target_type.is_numeric:
5815             self.is_py_target = False
5816             if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
5817                 raise error(self.pos, "Buffer indexing not allowed as for loop target.")
5818             self.loopvar_node = self.target
5819             self.py_loopvar_node = None
5820         else:
5821             self.is_py_target = True
5822             c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
5823             self.loopvar_node = c_loopvar_node
5824             self.py_loopvar_node = \
5825                 ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
5826         self.body = self.body.analyse_expressions(env)
5827         if self.else_clause:
5828             self.else_clause = self.else_clause.analyse_expressions(env)
5829         return self
5830
5831     def generate_execution_code(self, code):
5832         old_loop_labels = code.new_loop_labels()
5833         from_range = self.from_range
5834         self.bound1.generate_evaluation_code(code)
5835         self.bound2.generate_evaluation_code(code)
5836         offset, incop = self.relation_table[self.relation1]
5837         if self.step is not None:
5838             self.step.generate_evaluation_code(code)
5839             step = self.step.result()
5840             incop = "%s=%s" % (incop[0], step)
5841         import ExprNodes
5842         if isinstance(self.loopvar_node, ExprNodes.TempNode):
5843             self.loopvar_node.allocate(code)
5844         if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
5845             self.py_loopvar_node.allocate(code)
5846         if from_range:
5847             loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
5848         else:
5849             loopvar_name = self.loopvar_node.result()
5850         code.putln(
5851             "for (%s = %s%s; %s %s %s; %s%s) {" % (
5852                 loopvar_name,
5853                 self.bound1.result(), offset,
5854                 loopvar_name, self.relation2, self.bound2.result(),
5855                 loopvar_name, incop))
5856         if self.py_loopvar_node:
5857             self.py_loopvar_node.generate_evaluation_code(code)
5858             self.target.generate_assignment_code(self.py_loopvar_node, code)
5859         elif from_range:
5860             code.putln("%s = %s;" % (
5861                             self.target.result(), loopvar_name))
5862         self.body.generate_execution_code(code)
5863         code.put_label(code.continue_label)
5864         if self.py_loopvar_node:
5865             # This mess is to make for..from loops with python targets behave
5866             # exactly like those with C targets with regards to re-assignment
5867             # of the loop variable.
5868             import ExprNodes
5869             if self.target.entry.is_pyglobal:
5870                 # We know target is a NameNode, this is the only ugly case.
5871                 target_node = ExprNodes.PyTempNode(self.target.pos, None)
5872                 target_node.allocate(code)
5873                 interned_cname = code.intern_identifier(self.target.entry.name)
5874                 if self.target.entry.scope.is_module_scope:
5875                     code.globalstate.use_utility_code(
5876                         UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c"))
5877                     lookup_func = '__Pyx_GetModuleGlobalName(%s)'
5878                 else:
5879                     code.globalstate.use_utility_code(
5880                         UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c"))
5881                     lookup_func = '__Pyx_GetNameInClass(%s, %%s)' % (
5882                         self.target.entry.scope.namespace_cname)
5883                 code.putln("%s = %s; %s" % (
5884                     target_node.result(),
5885                     lookup_func % interned_cname,
5886                     code.error_goto_if_null(target_node.result(), self.target.pos)))
5887                 code.put_gotref(target_node.result())
5888             else:
5889                 target_node = self.target
5890             from_py_node = ExprNodes.CoerceFromPyTypeNode(
5891                 self.loopvar_node.type, target_node, self.target.entry.scope)
5892             from_py_node.temp_code = loopvar_name
5893             from_py_node.generate_result_code(code)
5894             if self.target.entry.is_pyglobal:
5895                 code.put_decref(target_node.result(), target_node.type)
5896                 target_node.release(code)
5897         code.putln("}")
5898         if self.py_loopvar_node:
5899             # This is potentially wasteful, but we don't want the semantics to
5900             # depend on whether or not the loop is a python type.
5901             self.py_loopvar_node.generate_evaluation_code(code)
5902             self.target.generate_assignment_code(self.py_loopvar_node, code)
5903         if from_range:
5904             code.funcstate.release_temp(loopvar_name)
5905         break_label = code.break_label
5906         code.set_loop_labels(old_loop_labels)
5907         if self.else_clause:
5908             code.putln("/*else*/ {")
5909             self.else_clause.generate_execution_code(code)
5910             code.putln("}")
5911         code.put_label(break_label)
5912         self.bound1.generate_disposal_code(code)
5913         self.bound1.free_temps(code)
5914         self.bound2.generate_disposal_code(code)
5915         self.bound2.free_temps(code)
5916         if isinstance(self.loopvar_node, ExprNodes.TempNode):
5917             self.loopvar_node.release(code)
5918         if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
5919             self.py_loopvar_node.release(code)
5920         if self.step is not None:
5921             self.step.generate_disposal_code(code)
5922             self.step.free_temps(code)
5923
5924     relation_table = {
5925         # {relop : (initial offset, increment op)}
5926         '<=': ("",   "++"),
5927         '<' : ("+1", "++"),
5928         '>=': ("",   "--"),
5929         '>' : ("-1", "--")
5930     }
5931
5932     def generate_function_definitions(self, env, code):
5933         self.target.generate_function_definitions(env, code)
5934         self.bound1.generate_function_definitions(env, code)
5935         self.bound2.generate_function_definitions(env, code)
5936         if self.step is not None:
5937             self.step.generate_function_definitions(env, code)
5938         self.body.generate_function_definitions(env, code)
5939         if self.else_clause is not None:
5940             self.else_clause.generate_function_definitions(env, code)
5941
5942     def annotate(self, code):
5943         self.target.annotate(code)
5944         self.bound1.annotate(code)
5945         self.bound2.annotate(code)
5946         if self.step:
5947             self.step.annotate(code)
5948         self.body.annotate(code)
5949         if self.else_clause:
5950             self.else_clause.annotate(code)
5951
5952
5953 class WithStatNode(StatNode):
5954     """
5955     Represents a Python with statement.
5956
5957     Implemented by the WithTransform as follows:
5958
5959         MGR = EXPR
5960         EXIT = MGR.__exit__
5961         VALUE = MGR.__enter__()
5962         EXC = True
5963         try:
5964             try:
5965                 TARGET = VALUE  # optional
5966                 BODY
5967             except:
5968                 EXC = False
5969                 if not EXIT(*EXCINFO):
5970                     raise
5971         finally:
5972             if EXC:
5973                 EXIT(None, None, None)
5974             MGR = EXIT = VALUE = None
5975     """
5976     #  manager          The with statement manager object
5977     #  target           ExprNode  the target lhs of the __enter__() call
5978     #  body             StatNode
5979     #  enter_call       ExprNode  the call to the __enter__() method
5980     #  exit_var         String    the cname of the __exit__() method reference
5981
5982     child_attrs = ["manager", "enter_call", "target", "body"]
5983
5984     enter_call = None
5985
5986     def analyse_declarations(self, env):
5987         self.manager.analyse_declarations(env)
5988         self.enter_call.analyse_declarations(env)
5989         self.body.analyse_declarations(env)
5990
5991     def analyse_expressions(self, env):
5992         self.manager = self.manager.analyse_types(env)
5993         self.enter_call = self.enter_call.analyse_types(env)
5994         self.body = self.body.analyse_expressions(env)
5995         return self
5996
5997     def generate_function_definitions(self, env, code):
5998         self.manager.generate_function_definitions(env, code)
5999         self.enter_call.generate_function_definitions(env, code)
6000         self.body.generate_function_definitions(env, code)
6001
6002     def generate_execution_code(self, code):
6003         code.putln("/*with:*/ {")
6004         self.manager.generate_evaluation_code(code)
6005         self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
6006         code.globalstate.use_utility_code(
6007             UtilityCode.load_cached("PyObjectLookupSpecial", "ObjectHandling.c"))
6008         code.putln("%s = __Pyx_PyObject_LookupSpecial(%s, %s); %s" % (
6009             self.exit_var,
6010             self.manager.py_result(),
6011             code.intern_identifier(EncodedString('__exit__')),
6012             code.error_goto_if_null(self.exit_var, self.pos),
6013             ))
6014         code.put_gotref(self.exit_var)
6015
6016         # need to free exit_var in the face of exceptions during setup
6017         old_error_label = code.new_error_label()
6018         intermediate_error_label = code.error_label
6019
6020         self.enter_call.generate_evaluation_code(code)
6021         if not self.target:
6022             self.enter_call.generate_disposal_code(code)
6023             self.enter_call.free_temps(code)
6024         else:
6025             # Otherwise, the node will be cleaned up by the
6026             # WithTargetAssignmentStatNode after assigning its result
6027             # to the target of the 'with' statement.
6028             pass
6029         self.manager.generate_disposal_code(code)
6030         self.manager.free_temps(code)
6031
6032         code.error_label = old_error_label
6033         self.body.generate_execution_code(code)
6034
6035         if code.label_used(intermediate_error_label):
6036             step_over_label = code.new_label()
6037             code.put_goto(step_over_label)
6038             code.put_label(intermediate_error_label)
6039             code.put_decref_clear(self.exit_var, py_object_type)
6040             code.put_goto(old_error_label)
6041             code.put_label(step_over_label)
6042
6043         code.funcstate.release_temp(self.exit_var)
6044         code.putln('}')
6045
6046 class WithTargetAssignmentStatNode(AssignmentNode):
6047     # The target assignment of the 'with' statement value (return
6048     # value of the __enter__() call).
6049     #
6050     # This is a special cased assignment that steals the RHS reference
6051     # and frees its temp.
6052     #
6053     # lhs       ExprNode   the assignment target
6054     # rhs       CloneNode  a (coerced) CloneNode for the orig_rhs (not owned by this node)
6055     # orig_rhs  ExprNode   the original ExprNode of the rhs. this node will clean up the
6056     #                      temps of the orig_rhs. basically, it takes ownership of the node
6057     #                      when the WithStatNode is done with it.
6058
6059     child_attrs = ["lhs"]
6060
6061     def analyse_declarations(self, env):
6062         self.lhs.analyse_target_declaration(env)
6063
6064     def analyse_expressions(self, env):
6065         self.rhs = self.rhs.analyse_types(env)
6066         self.lhs = self.lhs.analyse_target_types(env)
6067         self.lhs.gil_assignment_check(env)
6068         self.rhs = self.rhs.coerce_to(self.lhs.type, env)
6069         return self
6070
6071     def generate_execution_code(self, code):
6072         if self.orig_rhs.type.is_pyobject:
6073             # make sure rhs gets freed on errors, see below
6074             old_error_label = code.new_error_label()
6075             intermediate_error_label = code.error_label
6076
6077         self.rhs.generate_evaluation_code(code)
6078         self.lhs.generate_assignment_code(self.rhs, code)
6079
6080         if self.orig_rhs.type.is_pyobject:
6081             self.orig_rhs.generate_disposal_code(code)
6082             code.error_label = old_error_label
6083             if code.label_used(intermediate_error_label):
6084                 step_over_label = code.new_label()
6085                 code.put_goto(step_over_label)
6086                 code.put_label(intermediate_error_label)
6087                 self.orig_rhs.generate_disposal_code(code)
6088                 code.put_goto(old_error_label)
6089                 code.put_label(step_over_label)
6090
6091         self.orig_rhs.free_temps(code)
6092
6093     def annotate(self, code):
6094         self.lhs.annotate(code)
6095         self.rhs.annotate(code)
6096
6097
6098 class TryExceptStatNode(StatNode):
6099     #  try .. except statement
6100     #
6101     #  body             StatNode
6102     #  except_clauses   [ExceptClauseNode]
6103     #  else_clause      StatNode or None
6104
6105     child_attrs = ["body", "except_clauses", "else_clause"]
6106
6107     def analyse_declarations(self, env):
6108         self.body.analyse_declarations(env)
6109         for except_clause in self.except_clauses:
6110             except_clause.analyse_declarations(env)
6111         if self.else_clause:
6112             self.else_clause.analyse_declarations(env)
6113
6114     def analyse_expressions(self, env):
6115         self.body = self.body.analyse_expressions(env)
6116         default_clause_seen = 0
6117         for i, except_clause in enumerate(self.except_clauses):
6118             except_clause = self.except_clauses[i] = except_clause.analyse_expressions(env)
6119             if default_clause_seen:
6120                 error(except_clause.pos, "default 'except:' must be last")
6121             if not except_clause.pattern:
6122                 default_clause_seen = 1
6123         self.has_default_clause = default_clause_seen
6124         if self.else_clause:
6125             self.else_clause = self.else_clause.analyse_expressions(env)
6126         return self
6127
6128     nogil_check = Node.gil_error
6129     gil_message = "Try-except statement"
6130
6131     def generate_execution_code(self, code):
6132         old_return_label = code.return_label
6133         old_break_label = code.break_label
6134         old_continue_label = code.continue_label
6135         old_error_label = code.new_error_label()
6136         our_error_label = code.error_label
6137         except_end_label = code.new_label('exception_handled')
6138         except_error_label = code.new_label('except_error')
6139         except_return_label = code.new_label('except_return')
6140         try_return_label = code.new_label('try_return')
6141         try_break_label = code.new_label('try_break')
6142         try_continue_label = code.new_label('try_continue')
6143         try_end_label = code.new_label('try_end')
6144
6145         exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False)
6146                          for _ in xrange(3)]
6147         code.putln("{")
6148         save_exc = code.insertion_point()
6149         code.putln(
6150             "/*try:*/ {")
6151         code.return_label = try_return_label
6152         code.break_label = try_break_label
6153         code.continue_label = try_continue_label
6154         self.body.generate_execution_code(code)
6155         code.putln(
6156             "}")
6157         temps_to_clean_up = code.funcstate.all_free_managed_temps()
6158         can_raise = code.label_used(our_error_label)
6159
6160         if can_raise:
6161             # inject code before the try block to save away the exception state
6162             code.globalstate.use_utility_code(reset_exception_utility_code)
6163             save_exc.putln("__Pyx_ExceptionSave(%s);" %
6164                            ', '.join(['&%s' % var for var in exc_save_vars]))
6165             for var in exc_save_vars:
6166                 save_exc.put_xgotref(var)
6167
6168             def restore_saved_exception():
6169                 for name in exc_save_vars:
6170                     code.put_xgiveref(name)
6171                 code.putln("__Pyx_ExceptionReset(%s);" %
6172                            ', '.join(exc_save_vars))
6173         else:
6174             # try block cannot raise exceptions, but we had to allocate the temps above,
6175             # so just keep the C compiler from complaining about them being unused
6176             save_exc.putln("if (%s); else {/*mark used*/};" % '||'.join(exc_save_vars))
6177
6178             def restore_saved_exception():
6179                 pass
6180
6181         code.error_label = except_error_label
6182         code.return_label = except_return_label
6183         if self.else_clause:
6184             code.putln(
6185                 "/*else:*/ {")
6186             self.else_clause.generate_execution_code(code)
6187             code.putln(
6188                 "}")
6189
6190         if can_raise:
6191             for var in exc_save_vars:
6192                 code.put_xdecref_clear(var, py_object_type)
6193             code.put_goto(try_end_label)
6194             code.put_label(our_error_label)
6195             for temp_name, temp_type in temps_to_clean_up:
6196                 code.put_xdecref_clear(temp_name, temp_type)
6197             for except_clause in self.except_clauses:
6198                 except_clause.generate_handling_code(code, except_end_label)
6199             if not self.has_default_clause:
6200                 code.put_goto(except_error_label)
6201
6202         for exit_label, old_label in [(except_error_label, old_error_label),
6203                                       (try_break_label, old_break_label),
6204                                       (try_continue_label, old_continue_label),
6205                                       (try_return_label, old_return_label),
6206                                       (except_return_label, old_return_label)]:
6207             if code.label_used(exit_label):
6208                 if not code.label_used(try_end_label):
6209                     code.put_goto(try_end_label)
6210                 code.put_label(exit_label)
6211                 restore_saved_exception()
6212                 code.put_goto(old_label)
6213
6214         if code.label_used(except_end_label):
6215             if not code.label_used(try_end_label):
6216                 code.put_goto(try_end_label)
6217             code.put_label(except_end_label)
6218             restore_saved_exception()
6219         if code.label_used(try_end_label):
6220             code.put_label(try_end_label)
6221         code.putln("}")
6222
6223         for cname in exc_save_vars:
6224             code.funcstate.release_temp(cname)
6225
6226         code.return_label = old_return_label
6227         code.break_label = old_break_label
6228         code.continue_label = old_continue_label
6229         code.error_label = old_error_label
6230
6231     def generate_function_definitions(self, env, code):
6232         self.body.generate_function_definitions(env, code)
6233         for except_clause in self.except_clauses:
6234             except_clause.generate_function_definitions(env, code)
6235         if self.else_clause is not None:
6236             self.else_clause.generate_function_definitions(env, code)
6237
6238     def annotate(self, code):
6239         self.body.annotate(code)
6240         for except_node in self.except_clauses:
6241             except_node.annotate(code)
6242         if self.else_clause:
6243             self.else_clause.annotate(code)
6244
6245
6246 class ExceptClauseNode(Node):
6247     #  Part of try ... except statement.
6248     #
6249     #  pattern        [ExprNode]
6250     #  target         ExprNode or None
6251     #  body           StatNode
6252     #  excinfo_target TupleNode(3*ResultRefNode) or None   optional target for exception info (not owned here!)
6253     #  match_flag     string             result of exception match
6254     #  exc_value      ExcValueNode       used internally
6255     #  function_name  string             qualified name of enclosing function
6256     #  exc_vars       (string * 3)       local exception variables
6257     #  is_except_as   bool               Py3-style "except ... as xyz"
6258
6259     # excinfo_target is never set by the parser, but can be set by a transform
6260     # in order to extract more extensive information about the exception as a
6261     # sys.exc_info()-style tuple into a target variable
6262
6263     child_attrs = ["pattern", "target", "body", "exc_value"]
6264
6265     exc_value = None
6266     excinfo_target = None
6267     is_except_as = False
6268
6269     def analyse_declarations(self, env):
6270         if self.target:
6271             self.target.analyse_target_declaration(env)
6272         self.body.analyse_declarations(env)
6273
6274     def analyse_expressions(self, env):
6275         self.function_name = env.qualified_name
6276         if self.pattern:
6277             # normalise/unpack self.pattern into a list
6278             for i, pattern in enumerate(self.pattern):
6279                 pattern = pattern.analyse_expressions(env)
6280                 self.pattern[i] = pattern.coerce_to_pyobject(env)
6281
6282         if self.target:
6283             import ExprNodes
6284             self.exc_value = ExprNodes.ExcValueNode(self.pos)
6285             self.target = self.target.analyse_target_expression(env, self.exc_value)
6286
6287         self.body = self.body.analyse_expressions(env)
6288         return self
6289
6290     def generate_handling_code(self, code, end_label):
6291         code.mark_pos(self.pos)
6292         if self.pattern:
6293             exc_tests = []
6294             for pattern in self.pattern:
6295                 pattern.generate_evaluation_code(code)
6296                 exc_tests.append("PyErr_ExceptionMatches(%s)" % pattern.py_result())
6297
6298             match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
6299             code.putln(
6300                 "%s = %s;" % (match_flag, ' || '.join(exc_tests)))
6301             for pattern in self.pattern:
6302                 pattern.generate_disposal_code(code)
6303                 pattern.free_temps(code)
6304             code.putln(
6305                 "if (%s) {" %
6306                     match_flag)
6307             code.funcstate.release_temp(match_flag)
6308         else:
6309             code.putln("/*except:*/ {")
6310
6311         if (not getattr(self.body, 'stats', True)
6312                 and self.excinfo_target is None
6313                 and self.target is None):
6314             # most simple case: no exception variable, empty body (pass)
6315             # => reset the exception state, done
6316             code.putln("PyErr_Restore(0,0,0);")
6317             code.put_goto(end_label)
6318             code.putln("}")
6319             return
6320
6321         exc_vars = [code.funcstate.allocate_temp(py_object_type,
6322                                                  manage_ref=True)
6323                     for _ in xrange(3)]
6324         code.put_add_traceback(self.function_name)
6325         # We always have to fetch the exception value even if
6326         # there is no target, because this also normalises the
6327         # exception and stores it in the thread state.
6328         code.globalstate.use_utility_code(get_exception_utility_code)
6329         exc_args = "&%s, &%s, &%s" % tuple(exc_vars)
6330         code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
6331             code.error_goto(self.pos)))
6332         for x in exc_vars:
6333             code.put_gotref(x)
6334         if self.target:
6335             self.exc_value.set_var(exc_vars[1])
6336             self.exc_value.generate_evaluation_code(code)
6337             self.target.generate_assignment_code(self.exc_value, code)
6338         if self.excinfo_target is not None:
6339             for tempvar, node in zip(exc_vars, self.excinfo_target.args):
6340                 node.set_var(tempvar)
6341
6342         old_break_label, old_continue_label = code.break_label, code.continue_label
6343         code.break_label = code.new_label('except_break')
6344         code.continue_label = code.new_label('except_continue')
6345
6346         old_exc_vars = code.funcstate.exc_vars
6347         code.funcstate.exc_vars = exc_vars
6348         self.body.generate_execution_code(code)
6349         code.funcstate.exc_vars = old_exc_vars
6350         for var in exc_vars:
6351             code.put_decref_clear(var, py_object_type)
6352         code.put_goto(end_label)
6353
6354         for new_label, old_label in [(code.break_label, old_break_label),
6355                                      (code.continue_label, old_continue_label)]:
6356             if code.label_used(new_label):
6357                 code.put_label(new_label)
6358                 for var in exc_vars:
6359                     code.put_decref_clear(var, py_object_type)
6360                 code.put_goto(old_label)
6361         code.break_label = old_break_label
6362         code.continue_label = old_continue_label
6363
6364         for temp in exc_vars:
6365             code.funcstate.release_temp(temp)
6366
6367         code.putln(
6368             "}")
6369
6370     def generate_function_definitions(self, env, code):
6371         if self.target is not None:
6372             self.target.generate_function_definitions(env, code)
6373         self.body.generate_function_definitions(env, code)
6374
6375     def annotate(self, code):
6376         if self.pattern:
6377             for pattern in self.pattern:
6378                 pattern.annotate(code)
6379         if self.target:
6380             self.target.annotate(code)
6381         self.body.annotate(code)
6382
6383
6384 class TryFinallyStatNode(StatNode):
6385     #  try ... finally statement
6386     #
6387     #  body             StatNode
6388     #  finally_clause   StatNode
6389     #
6390     #  The plan is that we funnel all continue, break
6391     #  return and error gotos into the beginning of the
6392     #  finally block, setting a variable to remember which
6393     #  one we're doing. At the end of the finally block, we
6394     #  switch on the variable to figure out where to go.
6395     #  In addition, if we're doing an error, we save the
6396     #  exception on entry to the finally block and restore
6397     #  it on exit.
6398
6399     child_attrs = ["body", "finally_clause"]
6400
6401     preserve_exception = 1
6402
6403     # handle exception case, in addition to return/break/continue
6404     handle_error_case = True
6405     func_return_type = None
6406
6407     disallow_continue_in_try_finally = 0
6408     # There doesn't seem to be any point in disallowing
6409     # continue in the try block, since we have no problem
6410     # handling it.
6411
6412     is_try_finally_in_nogil = False
6413
6414     def create_analysed(pos, env, body, finally_clause):
6415         node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
6416         return node
6417     create_analysed = staticmethod(create_analysed)
6418
6419     def analyse_declarations(self, env):
6420         self.body.analyse_declarations(env)
6421         self.finally_clause.analyse_declarations(env)
6422
6423     def analyse_expressions(self, env):
6424         self.body = self.body.analyse_expressions(env)
6425         self.finally_clause = self.finally_clause.analyse_expressions(env)
6426         if env.return_type and not env.return_type.is_void:
6427             self.func_return_type = env.return_type
6428         return self
6429
6430     nogil_check = Node.gil_error
6431     gil_message = "Try-finally statement"
6432
6433     def generate_execution_code(self, code):
6434         old_error_label = code.error_label
6435         old_labels = code.all_new_labels()
6436         new_labels = code.get_all_labels()
6437         new_error_label = code.error_label
6438         if not self.handle_error_case:
6439             code.error_label = old_error_label
6440         catch_label = code.new_label()
6441
6442         code.putln("/*try:*/ {")
6443
6444         if self.disallow_continue_in_try_finally:
6445             was_in_try_finally = code.funcstate.in_try_finally
6446             code.funcstate.in_try_finally = 1
6447
6448         self.body.generate_execution_code(code)
6449
6450         if self.disallow_continue_in_try_finally:
6451             code.funcstate.in_try_finally = was_in_try_finally
6452
6453         code.putln("}")
6454         code.set_all_labels(old_labels)
6455
6456         temps_to_clean_up = code.funcstate.all_free_managed_temps()
6457         code.mark_pos(self.finally_clause.pos)
6458         code.putln("/*finally:*/ {")
6459
6460         def fresh_finally_clause(_next=[self.finally_clause]):
6461             # generate the original subtree once and always keep a fresh copy
6462             node = _next[0]
6463             node_copy = copy.deepcopy(node)
6464             if node is self.finally_clause:
6465                 _next[0] = node_copy
6466             else:
6467                 node = node_copy
6468             return node
6469
6470         preserve_error = self.preserve_exception and code.label_used(new_error_label)
6471         needs_success_cleanup = not self.finally_clause.is_terminator
6472
6473         if not self.body.is_terminator:
6474             code.putln('/*normal exit:*/{')
6475             fresh_finally_clause().generate_execution_code(code)
6476             if not self.finally_clause.is_terminator:
6477                 code.put_goto(catch_label)
6478             code.putln('}')
6479
6480         if preserve_error:
6481             code.putln('/*exception exit:*/{')
6482             if self.is_try_finally_in_nogil:
6483                 code.declare_gilstate()
6484             if needs_success_cleanup:
6485                 exc_lineno_cnames = tuple([
6486                     code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
6487                     for _ in range(2)])
6488                 exc_filename_cname = code.funcstate.allocate_temp(
6489                     PyrexTypes.CPtrType(PyrexTypes.c_const_type(PyrexTypes.c_char_type)),
6490                     manage_ref=False)
6491             else:
6492                 exc_lineno_cnames = exc_filename_cname = None
6493             exc_vars = tuple([
6494                 code.funcstate.allocate_temp(py_object_type, manage_ref=False)
6495                 for _ in range(6)])
6496             code.put_label(new_error_label)
6497             self.put_error_catcher(
6498                 code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname)
6499             finally_old_labels = code.all_new_labels()
6500
6501             code.putln('{')
6502             old_exc_vars = code.funcstate.exc_vars
6503             code.funcstate.exc_vars = exc_vars[:3]
6504             fresh_finally_clause().generate_execution_code(code)
6505             code.funcstate.exc_vars = old_exc_vars
6506             code.putln('}')
6507
6508             if needs_success_cleanup:
6509                 self.put_error_uncatcher(code, exc_vars, exc_lineno_cnames, exc_filename_cname)
6510                 if exc_lineno_cnames:
6511                     for cname in exc_lineno_cnames:
6512                         code.funcstate.release_temp(cname)
6513                 if exc_filename_cname:
6514                     code.funcstate.release_temp(exc_filename_cname)
6515                 code.put_goto(old_error_label)
6516
6517             for new_label, old_label in zip(code.get_all_labels(), finally_old_labels):
6518                 if not code.label_used(new_label):
6519                     continue
6520                 code.put_label(new_label)
6521                 self.put_error_cleaner(code, exc_vars)
6522                 code.put_goto(old_label)
6523
6524             for cname in exc_vars:
6525                 code.funcstate.release_temp(cname)
6526             code.putln('}')
6527
6528         code.set_all_labels(old_labels)
6529         return_label = code.return_label
6530         for i, (new_label, old_label) in enumerate(zip(new_labels, old_labels)):
6531             if not code.label_used(new_label):
6532                 continue
6533             if new_label == new_error_label and preserve_error:
6534                 continue  # handled above
6535
6536             code.put('%s: ' % new_label)
6537             code.putln('{')
6538             ret_temp = None
6539             if old_label == return_label and not self.finally_clause.is_terminator:
6540                 # store away return value for later reuse
6541                 if (self.func_return_type and
6542                         not self.is_try_finally_in_nogil and
6543                         not isinstance(self.finally_clause, GILExitNode)):
6544                     ret_temp = code.funcstate.allocate_temp(
6545                         self.func_return_type, manage_ref=False)
6546                     code.putln("%s = %s;" % (ret_temp, Naming.retval_cname))
6547                     if self.func_return_type.is_pyobject:
6548                         code.putln("%s = 0;" % Naming.retval_cname)
6549             fresh_finally_clause().generate_execution_code(code)
6550             if ret_temp:
6551                 code.putln("%s = %s;" % (Naming.retval_cname, ret_temp))
6552                 if self.func_return_type.is_pyobject:
6553                     code.putln("%s = 0;" % ret_temp)
6554                 code.funcstate.release_temp(ret_temp)
6555                 ret_temp = None
6556             if not self.finally_clause.is_terminator:
6557                 code.put_goto(old_label)
6558             code.putln('}')
6559
6560         # End finally
6561         code.put_label(catch_label)
6562         code.putln(
6563             "}")
6564
6565     def generate_function_definitions(self, env, code):
6566         self.body.generate_function_definitions(env, code)
6567         self.finally_clause.generate_function_definitions(env, code)
6568
6569     def put_error_catcher(self, code, temps_to_clean_up, exc_vars,
6570                           exc_lineno_cnames, exc_filename_cname):
6571         code.globalstate.use_utility_code(restore_exception_utility_code)
6572         code.globalstate.use_utility_code(get_exception_utility_code)
6573         code.globalstate.use_utility_code(swap_exception_utility_code)
6574
6575         code.putln(' '.join(["%s = 0;"]*len(exc_vars)) % exc_vars)
6576         if self.is_try_finally_in_nogil:
6577             code.put_ensure_gil(declare_gilstate=False)
6578
6579         for temp_name, type in temps_to_clean_up:
6580             code.put_xdecref_clear(temp_name, type)
6581
6582         # not using preprocessor here to avoid warnings about
6583         # unused utility functions and/or temps
6584         code.putln("if (PY_MAJOR_VERSION >= 3)"
6585                    " __Pyx_ExceptionSwap(&%s, &%s, &%s);" % exc_vars[3:])
6586         code.putln("if ((PY_MAJOR_VERSION < 3) ||"
6587                    # if __Pyx_GetException() fails in Py3,
6588                    # store the newly raised exception instead
6589                    " unlikely(__Pyx_GetException(&%s, &%s, &%s) < 0)) "
6590                    "__Pyx_ErrFetch(&%s, &%s, &%s);" % (exc_vars[:3] * 2))
6591         for var in exc_vars:
6592             code.put_xgotref(var)
6593         if exc_lineno_cnames:
6594             code.putln("%s = %s; %s = %s; %s = %s;" % (
6595                 exc_lineno_cnames[0], Naming.lineno_cname,
6596                 exc_lineno_cnames[1], Naming.clineno_cname,
6597                 exc_filename_cname, Naming.filename_cname))
6598
6599         if self.is_try_finally_in_nogil:
6600             code.put_release_ensured_gil()
6601
6602     def put_error_uncatcher(self, code, exc_vars, exc_lineno_cnames, exc_filename_cname):
6603         code.globalstate.use_utility_code(restore_exception_utility_code)
6604         code.globalstate.use_utility_code(reset_exception_utility_code)
6605
6606         if self.is_try_finally_in_nogil:
6607             code.put_ensure_gil(declare_gilstate=False)
6608
6609         # not using preprocessor here to avoid warnings about
6610         # unused utility functions and/or temps
6611         code.putln("if (PY_MAJOR_VERSION >= 3) {")
6612         for var in exc_vars[3:]:
6613             code.put_xgiveref(var)
6614         code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
6615         code.putln("}")
6616         for var in exc_vars[:3]:
6617             code.put_xgiveref(var)
6618         code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars[:3])
6619
6620         if self.is_try_finally_in_nogil:
6621             code.put_release_ensured_gil()
6622
6623         code.putln(' '.join(["%s = 0;"]*len(exc_vars)) % exc_vars)
6624         if exc_lineno_cnames:
6625             code.putln("%s = %s; %s = %s; %s = %s;" % (
6626                 Naming.lineno_cname, exc_lineno_cnames[0],
6627                 Naming.clineno_cname, exc_lineno_cnames[1],
6628                 Naming.filename_cname, exc_filename_cname))
6629
6630     def put_error_cleaner(self, code, exc_vars):
6631         code.globalstate.use_utility_code(reset_exception_utility_code)
6632         if self.is_try_finally_in_nogil:
6633             code.put_ensure_gil(declare_gilstate=False)
6634         # not using preprocessor here to avoid warnings about
6635         # unused utility functions and/or temps
6636         code.putln("if (PY_MAJOR_VERSION >= 3) {")
6637         for var in exc_vars[3:]:
6638             code.put_xgiveref(var)
6639         code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:])
6640         code.putln("}")
6641         for var in exc_vars[:3]:
6642             code.put_xdecref_clear(var, py_object_type)
6643         if self.is_try_finally_in_nogil:
6644             code.put_release_ensured_gil()
6645         code.putln(' '.join(["%s = 0;"]*3) % exc_vars[3:])
6646
6647     def annotate(self, code):
6648         self.body.annotate(code)
6649         self.finally_clause.annotate(code)
6650
6651
6652 class NogilTryFinallyStatNode(TryFinallyStatNode):
6653     """
6654     A try/finally statement that may be used in nogil code sections.
6655     """
6656
6657     preserve_exception = False
6658     nogil_check = None
6659
6660
6661 class GILStatNode(NogilTryFinallyStatNode):
6662     #  'with gil' or 'with nogil' statement
6663     #
6664     #   state   string   'gil' or 'nogil'
6665
6666     state_temp = None
6667
6668     def __init__(self, pos, state, body):
6669         self.state = state
6670         self.create_state_temp_if_needed(pos, state, body)
6671         TryFinallyStatNode.__init__(self, pos,
6672             body=body,
6673             finally_clause=GILExitNode(
6674                 pos, state=state, state_temp=self.state_temp))
6675
6676     def create_state_temp_if_needed(self, pos, state, body):
6677         from ParseTreeTransforms import YieldNodeCollector
6678         collector = YieldNodeCollector()
6679         collector.visitchildren(body)
6680         if not collector.yields:
6681             return
6682
6683         if state == 'gil':
6684             temp_type = PyrexTypes.c_gilstate_type
6685         else:
6686             temp_type = PyrexTypes.c_threadstate_ptr_type
6687         import ExprNodes
6688         self.state_temp = ExprNodes.TempNode(pos, temp_type)
6689
6690     def analyse_declarations(self, env):
6691         env._in_with_gil_block = (self.state == 'gil')
6692         if self.state == 'gil':
6693             env.has_with_gil_block = True
6694
6695         return super(GILStatNode, self).analyse_declarations(env)
6696
6697     def analyse_expressions(self, env):
6698         env.use_utility_code(
6699             UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
6700         was_nogil = env.nogil
6701         env.nogil = self.state == 'nogil'
6702         node = TryFinallyStatNode.analyse_expressions(self, env)
6703         env.nogil = was_nogil
6704         return node
6705
6706     def generate_execution_code(self, code):
6707         code.mark_pos(self.pos)
6708         code.begin_block()
6709         if self.state_temp:
6710             self.state_temp.allocate(code)
6711             variable = self.state_temp.result()
6712         else:
6713             variable = None
6714
6715         old_trace_config = code.funcstate.can_trace
6716         if self.state == 'gil':
6717             code.put_ensure_gil(variable=variable)
6718             # FIXME: not that easy, tracing may not be possible at all here
6719             #code.funcstate.can_trace = True
6720         else:
6721             code.put_release_gil(variable=variable)
6722             code.funcstate.can_trace = False
6723
6724         TryFinallyStatNode.generate_execution_code(self, code)
6725
6726         if self.state_temp:
6727             self.state_temp.release(code)
6728
6729         code.funcstate.can_trace = old_trace_config
6730         code.end_block()
6731
6732
6733 class GILExitNode(StatNode):
6734     """
6735     Used as the 'finally' block in a GILStatNode
6736
6737     state   string   'gil' or 'nogil'
6738     """
6739
6740     child_attrs = []
6741     state_temp = None
6742
6743     def analyse_expressions(self, env):
6744         return self
6745
6746     def generate_execution_code(self, code):
6747         if self.state_temp:
6748             variable = self.state_temp.result()
6749         else:
6750             variable = None
6751
6752         if self.state == 'gil':
6753             code.put_release_ensured_gil(variable)
6754         else:
6755             code.put_acquire_gil(variable)
6756
6757
6758 class EnsureGILNode(GILExitNode):
6759     """
6760     Ensure the GIL in nogil functions for cleanup before returning.
6761     """
6762
6763     def generate_execution_code(self, code):
6764         code.put_ensure_gil(declare_gilstate=False)
6765
6766 utility_code_for_cimports = {
6767     # utility code (or inlining c) in a pxd (or pyx) file.
6768     # TODO: Consider a generic user-level mechanism for importing
6769     'cpython.array'         : ("ArrayAPI", "arrayarray.h"),
6770     'cpython.array.array'   : ("ArrayAPI", "arrayarray.h"),
6771 }
6772
6773 class CImportStatNode(StatNode):
6774     #  cimport statement
6775     #
6776     #  module_name   string           Qualified name of module being imported
6777     #  as_name       string or None   Name specified in "as" clause, if any
6778
6779     child_attrs = []
6780
6781     def analyse_declarations(self, env):
6782         if not env.is_module_scope:
6783             error(self.pos, "cimport only allowed at module level")
6784             return
6785         module_scope = env.find_module(self.module_name, self.pos)
6786         if "." in self.module_name:
6787             names = [EncodedString(name) for name in self.module_name.split(".")]
6788             top_name = names[0]
6789             top_module_scope = env.context.find_submodule(top_name)
6790             module_scope = top_module_scope
6791             for name in names[1:]:
6792                 submodule_scope = module_scope.find_submodule(name)
6793                 module_scope.declare_module(name, submodule_scope, self.pos)
6794                 module_scope = submodule_scope
6795             if self.as_name:
6796                 env.declare_module(self.as_name, module_scope, self.pos)
6797             else:
6798                 env.add_imported_module(module_scope)
6799                 env.declare_module(top_name, top_module_scope, self.pos)
6800         else:
6801             name = self.as_name or self.module_name
6802             env.declare_module(name, module_scope, self.pos)
6803         if self.module_name in utility_code_for_cimports:
6804             env.use_utility_code(UtilityCode.load_cached(
6805                 *utility_code_for_cimports[self.module_name]))
6806
6807     def analyse_expressions(self, env):
6808         return self
6809
6810     def generate_execution_code(self, code):
6811         pass
6812
6813
6814 class FromCImportStatNode(StatNode):
6815     #  from ... cimport statement
6816     #
6817     #  module_name     string                        Qualified name of module
6818     #  imported_names  [(pos, name, as_name, kind)]  Names to be imported
6819
6820     child_attrs = []
6821
6822     def analyse_declarations(self, env):
6823         if not env.is_module_scope:
6824             error(self.pos, "cimport only allowed at module level")
6825             return
6826         module_scope = env.find_module(self.module_name, self.pos)
6827         env.add_imported_module(module_scope)
6828         for pos, name, as_name, kind in self.imported_names:
6829             if name == "*":
6830                 for local_name, entry in module_scope.entries.items():
6831                     env.add_imported_entry(local_name, entry, pos)
6832             else:
6833                 entry = module_scope.lookup(name)
6834                 if entry:
6835                     if kind and not self.declaration_matches(entry, kind):
6836                         entry.redeclared(pos)
6837                     entry.used = 1
6838                 else:
6839                     if kind == 'struct' or kind == 'union':
6840                         entry = module_scope.declare_struct_or_union(name,
6841                             kind = kind, scope = None, typedef_flag = 0, pos = pos)
6842                     elif kind == 'class':
6843                         entry = module_scope.declare_c_class(name, pos = pos,
6844                             module_name = self.module_name)
6845                     else:
6846                         submodule_scope = env.context.find_module(name, relative_to = module_scope, pos = self.pos)
6847                         if submodule_scope.parent_module is module_scope:
6848                             env.declare_module(as_name or name, submodule_scope, self.pos)
6849                         else:
6850                             error(pos, "Name '%s' not declared in module '%s'"
6851                                 % (name, self.module_name))
6852
6853                 if entry:
6854                     local_name = as_name or name
6855                     env.add_imported_entry(local_name, entry, pos)
6856
6857         if self.module_name.startswith('cpython'): # enough for now
6858             if self.module_name in utility_code_for_cimports:
6859                 env.use_utility_code(UtilityCode.load_cached(
6860                     *utility_code_for_cimports[self.module_name]))
6861             for _, name, _, _ in self.imported_names:
6862                 fqname = '%s.%s' % (self.module_name, name)
6863                 if fqname in utility_code_for_cimports:
6864                     env.use_utility_code(UtilityCode.load_cached(
6865                         *utility_code_for_cimports[fqname]))
6866
6867     def declaration_matches(self, entry, kind):
6868         if not entry.is_type:
6869             return 0
6870         type = entry.type
6871         if kind == 'class':
6872             if not type.is_extension_type:
6873                 return 0
6874         else:
6875             if not type.is_struct_or_union:
6876                 return 0
6877             if kind != type.kind:
6878                 return 0
6879         return 1
6880
6881     def analyse_expressions(self, env):
6882         return self
6883
6884     def generate_execution_code(self, code):
6885         pass
6886
6887
6888 class FromImportStatNode(StatNode):
6889     #  from ... import statement
6890     #
6891     #  module           ImportNode
6892     #  items            [(string, NameNode)]
6893     #  interned_items   [(string, NameNode, ExprNode)]
6894     #  item             PyTempNode            used internally
6895     #  import_star      boolean               used internally
6896
6897     child_attrs = ["module"]
6898     import_star = 0
6899
6900     def analyse_declarations(self, env):
6901         for name, target in self.items:
6902             if name == "*":
6903                 if not env.is_module_scope:
6904                     error(self.pos, "import * only allowed at module level")
6905                     return
6906                 env.has_import_star = 1
6907                 self.import_star = 1
6908             else:
6909                 target.analyse_target_declaration(env)
6910
6911     def analyse_expressions(self, env):
6912         import ExprNodes
6913         self.module = self.module.analyse_expressions(env)
6914         self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
6915         self.interned_items = []
6916         for name, target in self.items:
6917             if name == '*':
6918                 for _, entry in env.entries.items():
6919                     if not entry.is_type and entry.type.is_extension_type:
6920                         env.use_utility_code(UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c"))
6921                         break
6922             else:
6923                 entry =  env.lookup(target.name)
6924                 # check whether or not entry is already cimported
6925                 if (entry.is_type and entry.type.name == name
6926                         and hasattr(entry.type, 'module_name')):
6927                     if entry.type.module_name == self.module.module_name.value:
6928                         # cimported with absolute name
6929                         continue
6930                     try:
6931                         # cimported with relative name
6932                         module = env.find_module(self.module.module_name.value,
6933                                                  pos=None)
6934                         if entry.type.module_name == module.qualified_name:
6935                             continue
6936                     except AttributeError:
6937                         pass
6938                 target = target.analyse_target_expression(env, None)  # FIXME?
6939                 if target.type is py_object_type:
6940                     coerced_item = None
6941                 else:
6942                     coerced_item = self.item.coerce_to(target.type, env)
6943                 self.interned_items.append((name, target, coerced_item))
6944         return self
6945
6946     def generate_execution_code(self, code):
6947         self.module.generate_evaluation_code(code)
6948         if self.import_star:
6949             code.putln(
6950                 'if (%s(%s) < 0) %s;' % (
6951                     Naming.import_star,
6952                     self.module.py_result(),
6953                     code.error_goto(self.pos)))
6954         item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
6955         self.item.set_cname(item_temp)
6956         if self.interned_items:
6957             code.globalstate.use_utility_code(
6958                 UtilityCode.load_cached("ImportFrom", "ImportExport.c"))
6959         for name, target, coerced_item in self.interned_items:
6960             code.putln(
6961                 '%s = __Pyx_ImportFrom(%s, %s); %s' % (
6962                     item_temp,
6963                     self.module.py_result(),
6964                     code.intern_identifier(name),
6965                     code.error_goto_if_null(item_temp, self.pos)))
6966             code.put_gotref(item_temp)
6967             if coerced_item is None:
6968                 target.generate_assignment_code(self.item, code)
6969             else:
6970                 coerced_item.allocate_temp_result(code)
6971                 coerced_item.generate_result_code(code)
6972                 target.generate_assignment_code(coerced_item, code)
6973             code.put_decref_clear(item_temp, py_object_type)
6974         code.funcstate.release_temp(item_temp)
6975         self.module.generate_disposal_code(code)
6976         self.module.free_temps(code)
6977
6978
6979 class ParallelNode(Node):
6980     """
6981     Base class for cython.parallel constructs.
6982     """
6983
6984     nogil_check = None
6985
6986
6987 class ParallelStatNode(StatNode, ParallelNode):
6988     """
6989     Base class for 'with cython.parallel.parallel():' and 'for i in prange():'.
6990
6991     assignments     { Entry(var) : (var.pos, inplace_operator_or_None) }
6992                     assignments to variables in this parallel section
6993
6994     parent          parent ParallelStatNode or None
6995     is_parallel     indicates whether this node is OpenMP parallel
6996                     (true for #pragma omp parallel for and
6997                               #pragma omp parallel)
6998
6999     is_parallel is true for:
7000
7001         #pragma omp parallel
7002         #pragma omp parallel for
7003
7004     sections, but NOT for
7005
7006         #pragma omp for
7007
7008     We need this to determine the sharing attributes.
7009
7010     privatization_insertion_point   a code insertion point used to make temps
7011                                     private (esp. the "nsteps" temp)
7012
7013     args         tuple          the arguments passed to the parallel construct
7014     kwargs       DictNode       the keyword arguments passed to the parallel
7015                                 construct (replaced by its compile time value)
7016     """
7017
7018     child_attrs = ['body', 'num_threads']
7019
7020     body = None
7021
7022     is_prange = False
7023     is_nested_prange = False
7024
7025     error_label_used = False
7026
7027     num_threads = None
7028     chunksize = None
7029
7030     parallel_exc = (
7031         Naming.parallel_exc_type,
7032         Naming.parallel_exc_value,
7033         Naming.parallel_exc_tb,
7034     )
7035
7036     parallel_pos_info = (
7037         Naming.parallel_filename,
7038         Naming.parallel_lineno,
7039         Naming.parallel_clineno,
7040     )
7041
7042     pos_info = (
7043         Naming.filename_cname,
7044         Naming.lineno_cname,
7045         Naming.clineno_cname,
7046     )
7047
7048     critical_section_counter = 0
7049
7050     def __init__(self, pos, **kwargs):
7051         super(ParallelStatNode, self).__init__(pos, **kwargs)
7052
7053         # All assignments in this scope
7054         self.assignments = kwargs.get('assignments') or {}
7055
7056         # All seen closure cnames and their temporary cnames
7057         self.seen_closure_vars = set()
7058
7059         # Dict of variables that should be declared (first|last|)private or
7060         # reduction { Entry: (op, lastprivate) }.
7061         # If op is not None, it's a reduction.
7062         self.privates = {}
7063
7064         # [NameNode]
7065         self.assigned_nodes = []
7066
7067     def analyse_declarations(self, env):
7068         self.body.analyse_declarations(env)
7069
7070         self.num_threads = None
7071
7072         if self.kwargs:
7073             # Try to find num_threads and chunksize keyword arguments
7074             pairs = []
7075             for dictitem in self.kwargs.key_value_pairs:
7076                 if dictitem.key.value == 'num_threads':
7077                     self.num_threads = dictitem.value
7078                 elif self.is_prange and dictitem.key.value == 'chunksize':
7079                     self.chunksize = dictitem.value
7080                 else:
7081                     pairs.append(dictitem)
7082
7083             self.kwargs.key_value_pairs = pairs
7084
7085             try:
7086                 self.kwargs = self.kwargs.compile_time_value(env)
7087             except Exception, e:
7088                 error(self.kwargs.pos, "Only compile-time values may be "
7089                                        "supplied as keyword arguments")
7090         else:
7091             self.kwargs = {}
7092
7093         for kw, val in self.kwargs.iteritems():
7094             if kw not in self.valid_keyword_arguments:
7095                 error(self.pos, "Invalid keyword argument: %s" % kw)
7096             else:
7097                 setattr(self, kw, val)
7098
7099     def analyse_expressions(self, env):
7100         if self.num_threads:
7101             self.num_threads = self.num_threads.analyse_expressions(env)
7102
7103         if self.chunksize:
7104             self.chunksize = self.chunksize.analyse_expressions(env)
7105
7106         self.body = self.body.analyse_expressions(env)
7107         self.analyse_sharing_attributes(env)
7108
7109         if self.num_threads is not None:
7110             if (self.parent and self.parent.num_threads is not None and not
7111                                                     self.parent.is_prange):
7112                 error(self.pos,
7113                       "num_threads already declared in outer section")
7114             elif self.parent and not self.parent.is_prange:
7115                 error(self.pos,
7116                       "num_threads must be declared in the parent parallel section")
7117             elif (self.num_threads.type.is_int and
7118                   self.num_threads.is_literal and
7119                   self.num_threads.compile_time_value(env) <= 0):
7120                 error(self.pos,
7121                       "argument to num_threads must be greater than 0")
7122
7123             if not self.num_threads.is_simple():
7124                 self.num_threads = self.num_threads.coerce_to(
7125                     PyrexTypes.c_int_type, env).coerce_to_temp(env)
7126         return self
7127
7128     def analyse_sharing_attributes(self, env):
7129         """
7130         Analyse the privates for this block and set them in self.privates.
7131         This should be called in a post-order fashion during the
7132         analyse_expressions phase
7133         """
7134         for entry, (pos, op) in self.assignments.iteritems():
7135
7136             if self.is_prange and not self.is_parallel:
7137                 # closely nested prange in a with parallel block, disallow
7138                 # assigning to privates in the with parallel block (we
7139                 # consider it too implicit and magicky for users)
7140                 if entry in self.parent.assignments:
7141                     error(pos,
7142                           "Cannot assign to private of outer parallel block")
7143                     continue
7144
7145             if not self.is_prange and op:
7146                 # Again possible, but considered to magicky
7147                 error(pos, "Reductions not allowed for parallel blocks")
7148                 continue
7149
7150             # By default all variables should have the same values as if
7151             # executed sequentially
7152             lastprivate = True
7153             self.propagate_var_privatization(entry, pos, op, lastprivate)
7154
7155     def propagate_var_privatization(self, entry, pos, op, lastprivate):
7156         """
7157         Propagate the sharing attributes of a variable. If the privatization is
7158         determined by a parent scope, done propagate further.
7159
7160         If we are a prange, we propagate our sharing attributes outwards to
7161         other pranges. If we are a prange in parallel block and the parallel
7162         block does not determine the variable private, we propagate to the
7163         parent of the parent. Recursion stops at parallel blocks, as they have
7164         no concept of lastprivate or reduction.
7165
7166         So the following cases propagate:
7167
7168             sum is a reduction for all loops:
7169
7170                 for i in prange(n):
7171                     for j in prange(n):
7172                         for k in prange(n):
7173                             sum += i * j * k
7174
7175             sum is a reduction for both loops, local_var is private to the
7176             parallel with block:
7177
7178                 for i in prange(n):
7179                     with parallel:
7180                         local_var = ... # private to the parallel
7181                         for j in prange(n):
7182                             sum += i * j
7183
7184         Nested with parallel blocks are disallowed, because they wouldn't
7185         allow you to propagate lastprivates or reductions:
7186
7187             #pragma omp parallel for lastprivate(i)
7188             for i in prange(n):
7189
7190                 sum = 0
7191
7192                 #pragma omp parallel private(j, sum)
7193                 with parallel:
7194
7195                     #pragma omp parallel
7196                     with parallel:
7197
7198                         #pragma omp for lastprivate(j) reduction(+:sum)
7199                         for j in prange(n):
7200                             sum += i
7201
7202                     # sum and j are well-defined here
7203
7204                 # sum and j are undefined here
7205
7206             # sum and j are undefined here
7207         """
7208         self.privates[entry] = (op, lastprivate)
7209
7210         if entry.type.is_memoryviewslice:
7211             error(pos, "Memoryview slices can only be shared in parallel sections")
7212             return
7213
7214         if self.is_prange:
7215             if not self.is_parallel and entry not in self.parent.assignments:
7216                 # Parent is a parallel with block
7217                 parent = self.parent.parent
7218             else:
7219                 parent = self.parent
7220
7221             # We don't need to propagate privates, only reductions and
7222             # lastprivates
7223             if parent and (op or lastprivate):
7224                 parent.propagate_var_privatization(entry, pos, op, lastprivate)
7225
7226     def _allocate_closure_temp(self, code, entry):
7227         """
7228         Helper function that allocate a temporary for a closure variable that
7229         is assigned to.
7230         """
7231         if self.parent:
7232             return self.parent._allocate_closure_temp(code, entry)
7233
7234         if entry.cname in self.seen_closure_vars:
7235             return entry.cname
7236
7237         cname = code.funcstate.allocate_temp(entry.type, True)
7238
7239         # Add both the actual cname and the temp cname, as the actual cname
7240         # will be replaced with the temp cname on the entry
7241         self.seen_closure_vars.add(entry.cname)
7242         self.seen_closure_vars.add(cname)
7243
7244         self.modified_entries.append((entry, entry.cname))
7245         code.putln("%s = %s;" % (cname, entry.cname))
7246         entry.cname = cname
7247
7248     def initialize_privates_to_nan(self, code, exclude=None):
7249         first = True
7250
7251         for entry, (op, lastprivate) in self.privates.iteritems():
7252             if not op and (not exclude or entry != exclude):
7253                 invalid_value = entry.type.invalid_value()
7254
7255                 if invalid_value:
7256                     if first:
7257                         code.putln("/* Initialize private variables to "
7258                                    "invalid values */")
7259                         first = False
7260                     code.putln("%s = %s;" % (entry.cname,
7261                                              entry.type.cast_code(invalid_value)))
7262
7263     def evaluate_before_block(self, code, expr):
7264         c = self.begin_of_parallel_control_block_point_after_decls
7265         # we need to set the owner to ourselves temporarily, as
7266         # allocate_temp may generate a comment in the middle of our pragma
7267         # otherwise when DebugFlags.debug_temp_code_comments is in effect
7268         owner = c.funcstate.owner
7269         c.funcstate.owner = c
7270         expr.generate_evaluation_code(c)
7271         c.funcstate.owner = owner
7272
7273         return expr.result()
7274
7275     def put_num_threads(self, code):
7276         """
7277         Write self.num_threads if set as the num_threads OpenMP directive
7278         """
7279         if self.num_threads is not None:
7280             code.put(" num_threads(%s)" % self.evaluate_before_block(code,
7281                                                         self.num_threads))
7282
7283
7284     def declare_closure_privates(self, code):
7285         """
7286         If a variable is in a scope object, we need to allocate a temp and
7287         assign the value from the temp to the variable in the scope object
7288         after the parallel section. This kind of copying should be done only
7289         in the outermost parallel section.
7290         """
7291         self.modified_entries = []
7292
7293         for entry in self.assignments:
7294             if entry.from_closure or entry.in_closure:
7295                 self._allocate_closure_temp(code, entry)
7296
7297     def release_closure_privates(self, code):
7298         """
7299         Release any temps used for variables in scope objects. As this is the
7300         outermost parallel block, we don't need to delete the cnames from
7301         self.seen_closure_vars.
7302         """
7303         for entry, original_cname in self.modified_entries:
7304             code.putln("%s = %s;" % (original_cname, entry.cname))
7305             code.funcstate.release_temp(entry.cname)
7306             entry.cname = original_cname
7307
7308     def privatize_temps(self, code, exclude_temps=()):
7309         """
7310         Make any used temporaries private. Before the relevant code block
7311         code.start_collecting_temps() should have been called.
7312         """
7313         if self.is_parallel:
7314             c = self.privatization_insertion_point
7315
7316             self.temps = temps = code.funcstate.stop_collecting_temps()
7317             privates, firstprivates = [], []
7318             for temp, type in temps:
7319                 if type.is_pyobject or type.is_memoryviewslice:
7320                     firstprivates.append(temp)
7321                 else:
7322                     privates.append(temp)
7323
7324             if privates:
7325                 c.put(" private(%s)" % ", ".join(privates))
7326             if firstprivates:
7327                 c.put(" firstprivate(%s)" % ", ".join(firstprivates))
7328
7329             if self.breaking_label_used:
7330                 shared_vars = [Naming.parallel_why]
7331                 if self.error_label_used:
7332                     shared_vars.extend(self.parallel_exc)
7333                     c.put(" private(%s, %s, %s)" % self.pos_info)
7334
7335                 c.put(" shared(%s)" % ', '.join(shared_vars))
7336
7337     def cleanup_temps(self, code):
7338         # Now clean up any memoryview slice and object temporaries
7339         if self.is_parallel and not self.is_nested_prange:
7340             code.putln("/* Clean up any temporaries */")
7341             for temp, type in self.temps:
7342                 if type.is_memoryviewslice:
7343                     code.put_xdecref_memoryviewslice(temp, have_gil=False)
7344                 elif type.is_pyobject:
7345                     code.put_xdecref(temp, type)
7346                     code.putln("%s = NULL;" % temp)
7347
7348     def setup_parallel_control_flow_block(self, code):
7349         """
7350         Sets up a block that surrounds the parallel block to determine
7351         how the parallel section was exited. Any kind of return is
7352         trapped (break, continue, return, exceptions). This is the idea:
7353
7354         {
7355             int why = 0;
7356
7357             #pragma omp parallel
7358             {
7359                 return # -> goto new_return_label;
7360                 goto end_parallel;
7361
7362             new_return_label:
7363                 why = 3;
7364                 goto end_parallel;
7365
7366             end_parallel:;
7367                 #pragma omp flush(why) # we need to flush for every iteration
7368             }
7369
7370             if (why == 3)
7371                 goto old_return_label;
7372         }
7373         """
7374         self.old_loop_labels = code.new_loop_labels()
7375         self.old_error_label = code.new_error_label()
7376         self.old_return_label = code.return_label
7377         code.return_label = code.new_label(name="return")
7378
7379         code.begin_block() # parallel control flow block
7380         self.begin_of_parallel_control_block_point = code.insertion_point()
7381         self.begin_of_parallel_control_block_point_after_decls = code.insertion_point()
7382
7383         self.undef_builtin_expect_apple_gcc_bug(code)
7384
7385     def begin_parallel_block(self, code):
7386         """
7387         Each OpenMP thread in a parallel section that contains a with gil block
7388         must have the thread-state initialized. The call to
7389         PyGILState_Release() then deallocates our threadstate. If we wouldn't
7390         do this, each with gil block would allocate and deallocate one, thereby
7391         losing exception information before it can be saved before leaving the
7392         parallel section.
7393         """
7394         self.begin_of_parallel_block = code.insertion_point()
7395
7396     def end_parallel_block(self, code):
7397         """
7398         To ensure all OpenMP threads have thread states, we ensure the GIL
7399         in each thread (which creates a thread state if it doesn't exist),
7400         after which we release the GIL.
7401         On exit, reacquire the GIL and release the thread state.
7402
7403         If compiled without OpenMP support (at the C level), then we still have
7404         to acquire the GIL to decref any object temporaries.
7405         """
7406         if self.error_label_used:
7407             begin_code = self.begin_of_parallel_block
7408             end_code = code
7409
7410             begin_code.putln("#ifdef _OPENMP")
7411             begin_code.put_ensure_gil(declare_gilstate=True)
7412             begin_code.putln("Py_BEGIN_ALLOW_THREADS")
7413             begin_code.putln("#endif /* _OPENMP */")
7414
7415             end_code.putln("#ifdef _OPENMP")
7416             end_code.putln("Py_END_ALLOW_THREADS")
7417             end_code.putln("#else")
7418             end_code.put_safe("{\n")
7419             end_code.put_ensure_gil()
7420             end_code.putln("#endif /* _OPENMP */")
7421             self.cleanup_temps(end_code)
7422             end_code.put_release_ensured_gil()
7423             end_code.putln("#ifndef _OPENMP")
7424             end_code.put_safe("}\n")
7425             end_code.putln("#endif /* _OPENMP */")
7426
7427     def trap_parallel_exit(self, code, should_flush=False):
7428         """
7429         Trap any kind of return inside a parallel construct. 'should_flush'
7430         indicates whether the variable should be flushed, which is needed by
7431         prange to skip the loop. It also indicates whether we need to register
7432         a continue (we need this for parallel blocks, but not for prange
7433         loops, as it is a direct jump there).
7434
7435         It uses the same mechanism as try/finally:
7436             1 continue
7437             2 break
7438             3 return
7439             4 error
7440         """
7441         save_lastprivates_label = code.new_label()
7442         dont_return_label = code.new_label()
7443
7444         self.any_label_used = False
7445         self.breaking_label_used = False
7446         self.error_label_used = False
7447
7448         self.parallel_private_temps = []
7449
7450         all_labels = code.get_all_labels()
7451
7452         # Figure this out before starting to generate any code
7453         for label in all_labels:
7454             if code.label_used(label):
7455                 self.breaking_label_used = (self.breaking_label_used or
7456                                             label != code.continue_label)
7457                 self.any_label_used = True
7458
7459         if self.any_label_used:
7460             code.put_goto(dont_return_label)
7461
7462         for i, label in enumerate(all_labels):
7463             if not code.label_used(label):
7464                 continue
7465
7466             is_continue_label = label == code.continue_label
7467
7468             code.put_label(label)
7469
7470             if not (should_flush and is_continue_label):
7471                 if label == code.error_label:
7472                     self.error_label_used = True
7473                     self.fetch_parallel_exception(code)
7474
7475                 code.putln("%s = %d;" % (Naming.parallel_why, i + 1))
7476
7477             if (self.breaking_label_used and self.is_prange and not
7478                     is_continue_label):
7479                 code.put_goto(save_lastprivates_label)
7480             else:
7481                 code.put_goto(dont_return_label)
7482
7483         if self.any_label_used:
7484             if self.is_prange and self.breaking_label_used:
7485                 # Don't rely on lastprivate, save our lastprivates
7486                 code.put_label(save_lastprivates_label)
7487                 self.save_parallel_vars(code)
7488
7489             code.put_label(dont_return_label)
7490
7491             if should_flush and self.breaking_label_used:
7492                 code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_why)
7493
7494     def save_parallel_vars(self, code):
7495         """
7496         The following shenanigans are instated when we break, return or
7497         propagate errors from a prange. In this case we cannot rely on
7498         lastprivate() to do its job, as no iterations may have executed yet
7499         in the last thread, leaving the values undefined. It is most likely
7500         that the breaking thread has well-defined values of the lastprivate
7501         variables, so we keep those values.
7502         """
7503         section_name = ("__pyx_parallel_lastprivates%d" %
7504                                             self.critical_section_counter)
7505         code.putln_openmp("#pragma omp critical(%s)" % section_name)
7506         ParallelStatNode.critical_section_counter += 1
7507
7508         code.begin_block() # begin critical section
7509
7510         c = self.begin_of_parallel_control_block_point
7511
7512         temp_count = 0
7513         for entry, (op, lastprivate) in self.privates.iteritems():
7514             if not lastprivate or entry.type.is_pyobject:
7515                 continue
7516
7517             type_decl = entry.type.declaration_code("")
7518             temp_cname = "__pyx_parallel_temp%d" % temp_count
7519             private_cname = entry.cname
7520
7521             temp_count += 1
7522
7523             invalid_value = entry.type.invalid_value()
7524             if invalid_value:
7525                 init = ' = ' + invalid_value
7526             else:
7527                 init = ''
7528             # Declare the parallel private in the outer block
7529             c.putln("%s %s%s;" % (type_decl, temp_cname, init))
7530
7531             # Initialize before escaping
7532             code.putln("%s = %s;" % (temp_cname, private_cname))
7533
7534             self.parallel_private_temps.append((temp_cname, private_cname))
7535
7536         code.end_block() # end critical section
7537
7538     def fetch_parallel_exception(self, code):
7539         """
7540         As each OpenMP thread may raise an exception, we need to fetch that
7541         exception from the threadstate and save it for after the parallel
7542         section where it can be re-raised in the master thread.
7543
7544         Although it would seem that __pyx_filename, __pyx_lineno and
7545         __pyx_clineno are only assigned to under exception conditions (i.e.,
7546         when we have the GIL), and thus should be allowed to be shared without
7547         any race condition, they are in fact subject to the same race
7548         conditions that they were previously when they were global variables
7549         and functions were allowed to release the GIL:
7550
7551             thread A                thread B
7552                 acquire
7553                 set lineno
7554                 release
7555                                         acquire
7556                                         set lineno
7557                                         release
7558                 acquire
7559                 fetch exception
7560                 release
7561                                         skip the fetch
7562
7563                 deallocate threadstate  deallocate threadstate
7564         """
7565         code.begin_block()
7566         code.put_ensure_gil(declare_gilstate=True)
7567
7568         code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_exc_type)
7569         code.putln(
7570             "if (!%s) {" % Naming.parallel_exc_type)
7571
7572         code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % self.parallel_exc)
7573         pos_info = chain(*zip(self.parallel_pos_info, self.pos_info))
7574         code.funcstate.uses_error_indicator = True
7575         code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
7576         code.put_gotref(Naming.parallel_exc_type)
7577
7578         code.putln(
7579             "}")
7580
7581         code.put_release_ensured_gil()
7582         code.end_block()
7583
7584     def restore_parallel_exception(self, code):
7585         "Re-raise a parallel exception"
7586         code.begin_block()
7587         code.put_ensure_gil(declare_gilstate=True)
7588
7589         code.put_giveref(Naming.parallel_exc_type)
7590         code.putln("__Pyx_ErrRestore(%s, %s, %s);" % self.parallel_exc)
7591         pos_info = chain(*zip(self.pos_info, self.parallel_pos_info))
7592         code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
7593
7594         code.put_release_ensured_gil()
7595         code.end_block()
7596
7597     def restore_labels(self, code):
7598         """
7599         Restore all old labels. Call this before the 'else' clause to for
7600         loops and always before ending the parallel control flow block.
7601         """
7602         code.set_all_labels(self.old_loop_labels + (self.old_return_label,
7603                                                     self.old_error_label))
7604
7605     def end_parallel_control_flow_block(self, code,
7606                                         break_=False, continue_=False):
7607         """
7608         This ends the parallel control flow block and based on how the parallel
7609         section was exited, takes the corresponding action. The break_ and
7610         continue_ parameters indicate whether these should be propagated
7611         outwards:
7612
7613             for i in prange(...):
7614                 with cython.parallel.parallel():
7615                     continue
7616
7617         Here break should be trapped in the parallel block, and propagated to
7618         the for loop.
7619         """
7620         c = self.begin_of_parallel_control_block_point
7621
7622         # Firstly, always prefer errors over returning, continue or break
7623         if self.error_label_used:
7624             c.putln("const char *%s = NULL; int %s = 0, %s = 0;" %
7625                                                 self.parallel_pos_info)
7626
7627             c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" %
7628                                                         self.parallel_exc)
7629
7630             code.putln(
7631                 "if (%s) {" % Naming.parallel_exc_type)
7632             code.putln("/* This may have been overridden by a continue, "
7633                        "break or return in another thread. Prefer the error. */")
7634             code.putln("%s = 4;" % Naming.parallel_why)
7635             code.putln(
7636                 "}")
7637
7638         if continue_:
7639             any_label_used = self.any_label_used
7640         else:
7641             any_label_used = self.breaking_label_used
7642
7643         if any_label_used:
7644             # __pyx_parallel_why is used, declare and initialize
7645             c.putln("int %s;" % Naming.parallel_why)
7646             c.putln("%s = 0;" % Naming.parallel_why)
7647
7648             code.putln(
7649                 "if (%s) {" % Naming.parallel_why)
7650
7651             for temp_cname, private_cname in self.parallel_private_temps:
7652                 code.putln("%s = %s;" % (private_cname, temp_cname))
7653
7654             code.putln("switch (%s) {" % Naming.parallel_why)
7655             if continue_:
7656                 code.put("    case 1: ")
7657                 code.put_goto(code.continue_label)
7658
7659             if break_:
7660                 code.put("    case 2: ")
7661                 code.put_goto(code.break_label)
7662
7663             code.put("    case 3: ")
7664             code.put_goto(code.return_label)
7665
7666             if self.error_label_used:
7667                 code.globalstate.use_utility_code(restore_exception_utility_code)
7668                 code.putln("    case 4:")
7669                 self.restore_parallel_exception(code)
7670                 code.put_goto(code.error_label)
7671
7672             code.putln("}") # end switch
7673             code.putln(
7674                 "}") # end if
7675
7676         code.end_block() # end parallel control flow block
7677         self.redef_builtin_expect_apple_gcc_bug(code)
7678
7679     # FIXME: improve with version number for OS X Lion
7680     buggy_platform_macro_condition = "(defined(__APPLE__) || defined(__OSX__))"
7681     have_expect_condition = "(defined(__GNUC__) && " \
7682                              "(__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))"
7683     redef_condition = "(%s && %s)" % (buggy_platform_macro_condition, have_expect_condition)
7684
7685     def undef_builtin_expect_apple_gcc_bug(self, code):
7686         """
7687         A bug on OS X Lion disallows __builtin_expect macros. This code avoids them
7688         """
7689         if not self.parent:
7690             code.undef_builtin_expect(self.redef_condition)
7691
7692     def redef_builtin_expect_apple_gcc_bug(self, code):
7693         if not self.parent:
7694             code.redef_builtin_expect(self.redef_condition)
7695
7696
7697 class ParallelWithBlockNode(ParallelStatNode):
7698     """
7699     This node represents a 'with cython.parallel.parallel():' block
7700     """
7701
7702     valid_keyword_arguments = ['num_threads']
7703
7704     num_threads = None
7705
7706     def analyse_declarations(self, env):
7707         super(ParallelWithBlockNode, self).analyse_declarations(env)
7708         if self.args:
7709             error(self.pos, "cython.parallel.parallel() does not take "
7710                             "positional arguments")
7711
7712     def generate_execution_code(self, code):
7713         self.declare_closure_privates(code)
7714         self.setup_parallel_control_flow_block(code)
7715
7716         code.putln("#ifdef _OPENMP")
7717         code.put("#pragma omp parallel ")
7718
7719         if self.privates:
7720             privates = [e.cname for e in self.privates
7721                                     if not e.type.is_pyobject]
7722             code.put('private(%s)' % ', '.join(privates))
7723
7724         self.privatization_insertion_point = code.insertion_point()
7725         self.put_num_threads(code)
7726         code.putln("")
7727
7728         code.putln("#endif /* _OPENMP */")
7729
7730         code.begin_block() # parallel block
7731         self.begin_parallel_block(code)
7732         self.initialize_privates_to_nan(code)
7733         code.funcstate.start_collecting_temps()
7734         self.body.generate_execution_code(code)
7735         self.trap_parallel_exit(code)
7736         self.privatize_temps(code)
7737         self.end_parallel_block(code)
7738         code.end_block() # end parallel block
7739
7740         continue_ = code.label_used(code.continue_label)
7741         break_ = code.label_used(code.break_label)
7742
7743         self.restore_labels(code)
7744         self.end_parallel_control_flow_block(code, break_=break_,
7745                                              continue_=continue_)
7746         self.release_closure_privates(code)
7747
7748
7749 class ParallelRangeNode(ParallelStatNode):
7750     """
7751     This node represents a 'for i in cython.parallel.prange():' construct.
7752
7753     target       NameNode       the target iteration variable
7754     else_clause  Node or None   the else clause of this loop
7755     """
7756
7757     child_attrs = ['body', 'target', 'else_clause', 'args', 'num_threads',
7758                    'chunksize']
7759
7760     body = target = else_clause = args = None
7761
7762     start = stop = step = None
7763
7764     is_prange = True
7765
7766     nogil = None
7767     schedule = None
7768
7769     valid_keyword_arguments = ['schedule', 'nogil', 'num_threads', 'chunksize']
7770
7771     def __init__(self, pos, **kwds):
7772         super(ParallelRangeNode, self).__init__(pos, **kwds)
7773         # Pretend to be a ForInStatNode for control flow analysis
7774         self.iterator = PassStatNode(pos)
7775
7776     def analyse_declarations(self, env):
7777         super(ParallelRangeNode, self).analyse_declarations(env)
7778         self.target.analyse_target_declaration(env)
7779         if self.else_clause is not None:
7780             self.else_clause.analyse_declarations(env)
7781
7782         if not self.args or len(self.args) > 3:
7783             error(self.pos, "Invalid number of positional arguments to prange")
7784             return
7785
7786         if len(self.args) == 1:
7787             self.stop, = self.args
7788         elif len(self.args) == 2:
7789             self.start, self.stop = self.args
7790         else:
7791             self.start, self.stop, self.step = self.args
7792
7793         if hasattr(self.schedule, 'decode'):
7794             self.schedule = self.schedule.decode('ascii')
7795
7796         if self.schedule not in (None, 'static', 'dynamic', 'guided',
7797                                  'runtime'):
7798             error(self.pos, "Invalid schedule argument to prange: %s" %
7799                                                         (self.schedule,))
7800
7801     def analyse_expressions(self, env):
7802         was_nogil = env.nogil
7803         if self.nogil:
7804             env.nogil = True
7805
7806         if self.target is None:
7807             error(self.pos, "prange() can only be used as part of a for loop")
7808             return self
7809
7810         self.target = self.target.analyse_target_types(env)
7811
7812         if not self.target.type.is_numeric:
7813             # Not a valid type, assume one for now anyway
7814
7815             if not self.target.type.is_pyobject:
7816                 # nogil_check will catch the is_pyobject case
7817                 error(self.target.pos,
7818                       "Must be of numeric type, not %s" % self.target.type)
7819
7820             self.index_type = PyrexTypes.c_py_ssize_t_type
7821         else:
7822             self.index_type = self.target.type
7823             if not self.index_type.signed:
7824                 warning(self.target.pos,
7825                         "Unsigned index type not allowed before OpenMP 3.0",
7826                         level=2)
7827
7828         # Setup start, stop and step, allocating temps if needed
7829         self.names = 'start', 'stop', 'step'
7830         start_stop_step = self.start, self.stop, self.step
7831
7832         for node, name in zip(start_stop_step, self.names):
7833             if node is not None:
7834                 node.analyse_types(env)
7835                 if not node.type.is_numeric:
7836                     error(node.pos, "%s argument must be numeric" % name)
7837                     continue
7838
7839                 if not node.is_literal:
7840                     node = node.coerce_to_temp(env)
7841                     setattr(self, name, node)
7842
7843                 # As we range from 0 to nsteps, computing the index along the
7844                 # way, we need a fitting type for 'i' and 'nsteps'
7845                 self.index_type = PyrexTypes.widest_numeric_type(
7846                                         self.index_type, node.type)
7847
7848         if self.else_clause is not None:
7849             self.else_clause = self.else_clause.analyse_expressions(env)
7850
7851         # Although not actually an assignment in this scope, it should be
7852         # treated as such to ensure it is unpacked if a closure temp, and to
7853         # ensure lastprivate behaviour and propagation. If the target index is
7854         # not a NameNode, it won't have an entry, and an error was issued by
7855         # ParallelRangeTransform
7856         if hasattr(self.target, 'entry'):
7857             self.assignments[self.target.entry] = self.target.pos, None
7858
7859         node = super(ParallelRangeNode, self).analyse_expressions(env)
7860
7861         if node.chunksize:
7862             if not node.schedule:
7863                 error(node.chunksize.pos,
7864                       "Must provide schedule with chunksize")
7865             elif node.schedule == 'runtime':
7866                 error(node.chunksize.pos,
7867                       "Chunksize not valid for the schedule runtime")
7868             elif (node.chunksize.type.is_int and
7869                   node.chunksize.is_literal and
7870                   node.chunksize.compile_time_value(env) <= 0):
7871                 error(node.chunksize.pos, "Chunksize must not be negative")
7872
7873             node.chunksize = node.chunksize.coerce_to(
7874                 PyrexTypes.c_int_type, env).coerce_to_temp(env)
7875
7876         if node.nogil:
7877             env.nogil = was_nogil
7878
7879         node.is_nested_prange = node.parent and node.parent.is_prange
7880         if node.is_nested_prange:
7881             parent = node
7882             while parent.parent and parent.parent.is_prange:
7883                 parent = parent.parent
7884
7885             parent.assignments.update(node.assignments)
7886             parent.privates.update(node.privates)
7887             parent.assigned_nodes.extend(node.assigned_nodes)
7888         return node
7889
7890     def nogil_check(self, env):
7891         names = 'start', 'stop', 'step', 'target'
7892         nodes = self.start, self.stop, self.step, self.target
7893         for name, node in zip(names, nodes):
7894             if node is not None and node.type.is_pyobject:
7895                 error(node.pos, "%s may not be a Python object "
7896                                 "as we don't have the GIL" % name)
7897
7898     def generate_execution_code(self, code):
7899         """
7900         Generate code in the following steps
7901
7902             1)  copy any closure variables determined thread-private
7903                 into temporaries
7904
7905             2)  allocate temps for start, stop and step
7906
7907             3)  generate a loop that calculates the total number of steps,
7908                 which then computes the target iteration variable for every step:
7909
7910                     for i in prange(start, stop, step):
7911                         ...
7912
7913                 becomes
7914
7915                     nsteps = (stop - start) / step;
7916                     i = start;
7917
7918                     #pragma omp parallel for lastprivate(i)
7919                     for (temp = 0; temp < nsteps; temp++) {
7920                         i = start + step * temp;
7921                         ...
7922                     }
7923
7924                 Note that accumulation of 'i' would have a data dependency
7925                 between iterations.
7926
7927                 Also, you can't do this
7928
7929                     for (i = start; i < stop; i += step)
7930                         ...
7931
7932                 as the '<' operator should become '>' for descending loops.
7933                 'for i from x < i < y:' does not suffer from this problem
7934                 as the relational operator is known at compile time!
7935
7936             4) release our temps and write back any private closure variables
7937         """
7938         self.declare_closure_privates(code)
7939
7940         # This can only be a NameNode
7941         target_index_cname = self.target.entry.cname
7942
7943         # This will be used as the dict to format our code strings, holding
7944         # the start, stop , step, temps and target cnames
7945         fmt_dict = {
7946             'target': target_index_cname,
7947         }
7948
7949         # Setup start, stop and step, allocating temps if needed
7950         start_stop_step = self.start, self.stop, self.step
7951         defaults = '0', '0', '1'
7952         for node, name, default in zip(start_stop_step, self.names, defaults):
7953             if node is None:
7954                 result = default
7955             elif node.is_literal:
7956                 result = node.get_constant_c_result_code()
7957             else:
7958                 node.generate_evaluation_code(code)
7959                 result = node.result()
7960
7961             fmt_dict[name] = result
7962
7963         fmt_dict['i'] = code.funcstate.allocate_temp(self.index_type, False)
7964         fmt_dict['nsteps'] = code.funcstate.allocate_temp(self.index_type, False)
7965
7966         # TODO: check if the step is 0 and if so, raise an exception in a
7967         # 'with gil' block. For now, just abort
7968         code.putln("if (%(step)s == 0) abort();" % fmt_dict)
7969
7970         self.setup_parallel_control_flow_block(code) # parallel control flow block
7971
7972         self.control_flow_var_code_point = code.insertion_point()
7973
7974         # Note: nsteps is private in an outer scope if present
7975         code.putln("%(nsteps)s = (%(stop)s - %(start)s) / %(step)s;" % fmt_dict)
7976
7977         # The target iteration variable might not be initialized, do it only if
7978         # we are executing at least 1 iteration, otherwise we should leave the
7979         # target unaffected. The target iteration variable is firstprivate to
7980         # shut up compiler warnings caused by lastprivate, as the compiler
7981         # erroneously believes that nsteps may be <= 0, leaving the private
7982         # target index uninitialized
7983         code.putln("if (%(nsteps)s > 0)" % fmt_dict)
7984         code.begin_block() # if block
7985         self.generate_loop(code, fmt_dict)
7986         code.end_block() # end if block
7987
7988         self.restore_labels(code)
7989
7990         if self.else_clause:
7991             if self.breaking_label_used:
7992                 code.put("if (%s < 2)" % Naming.parallel_why)
7993
7994             code.begin_block() # else block
7995             code.putln("/* else */")
7996             self.else_clause.generate_execution_code(code)
7997             code.end_block() # end else block
7998
7999         # ------ cleanup ------
8000         self.end_parallel_control_flow_block(code) # end parallel control flow block
8001
8002         # And finally, release our privates and write back any closure
8003         # variables
8004         for temp in start_stop_step:
8005             if temp is not None:
8006                 temp.generate_disposal_code(code)
8007                 temp.free_temps(code)
8008
8009         code.funcstate.release_temp(fmt_dict['i'])
8010         code.funcstate.release_temp(fmt_dict['nsteps'])
8011
8012         self.release_closure_privates(code)
8013
8014     def generate_loop(self, code, fmt_dict):
8015         if self.is_nested_prange:
8016             code.putln("#if 0")
8017         else:
8018             code.putln("#ifdef _OPENMP")
8019
8020         if not self.is_parallel:
8021             code.put("#pragma omp for")
8022             self.privatization_insertion_point = code.insertion_point()
8023             reduction_codepoint = self.parent.privatization_insertion_point
8024         else:
8025             code.put("#pragma omp parallel")
8026             self.privatization_insertion_point = code.insertion_point()
8027             reduction_codepoint = self.privatization_insertion_point
8028             code.putln("")
8029             code.putln("#endif /* _OPENMP */")
8030
8031             code.begin_block() # pragma omp parallel begin block
8032
8033             # Initialize the GIL if needed for this thread
8034             self.begin_parallel_block(code)
8035
8036             if self.is_nested_prange:
8037                 code.putln("#if 0")
8038             else:
8039                 code.putln("#ifdef _OPENMP")
8040             code.put("#pragma omp for")
8041
8042         for entry, (op, lastprivate) in self.privates.iteritems():
8043             # Don't declare the index variable as a reduction
8044             if op and op in "+*-&^|" and entry != self.target.entry:
8045                 if entry.type.is_pyobject:
8046                     error(self.pos, "Python objects cannot be reductions")
8047                 else:
8048                     #code.put(" reduction(%s:%s)" % (op, entry.cname))
8049                     # This is the only way reductions + nesting works in gcc4.5
8050                     reduction_codepoint.put(
8051                                 " reduction(%s:%s)" % (op, entry.cname))
8052             else:
8053                 if entry == self.target.entry:
8054                     code.put(" firstprivate(%s)" % entry.cname)
8055                     code.put(" lastprivate(%s)" % entry.cname)
8056                     continue
8057
8058                 if not entry.type.is_pyobject:
8059                     if lastprivate:
8060                         private = 'lastprivate'
8061                     else:
8062                         private = 'private'
8063
8064                     code.put(" %s(%s)" % (private, entry.cname))
8065
8066         if self.schedule:
8067             if self.chunksize:
8068                 chunksize = ", %s" % self.evaluate_before_block(code,
8069                                                                 self.chunksize)
8070             else:
8071                 chunksize = ""
8072
8073             code.put(" schedule(%s%s)" % (self.schedule, chunksize))
8074
8075         self.put_num_threads(reduction_codepoint)
8076
8077         code.putln("")
8078         code.putln("#endif /* _OPENMP */")
8079
8080         code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict)
8081         code.begin_block() # for loop block
8082
8083         guard_around_body_codepoint = code.insertion_point()
8084
8085         # Start if guard block around the body. This may be unnecessary, but
8086         # at least it doesn't spoil indentation
8087         code.begin_block()
8088
8089         code.putln("%(target)s = %(start)s + %(step)s * %(i)s;" % fmt_dict)
8090         self.initialize_privates_to_nan(code, exclude=self.target.entry)
8091
8092         if self.is_parallel:
8093             code.funcstate.start_collecting_temps()
8094
8095         self.body.generate_execution_code(code)
8096         self.trap_parallel_exit(code, should_flush=True)
8097         self.privatize_temps(code)
8098
8099         if self.breaking_label_used:
8100             # Put a guard around the loop body in case return, break or
8101             # exceptions might be used
8102             guard_around_body_codepoint.putln("if (%s < 2)" % Naming.parallel_why)
8103
8104         code.end_block() # end guard around loop body
8105         code.end_block() # end for loop block
8106
8107         if self.is_parallel:
8108             # Release the GIL and deallocate the thread state
8109             self.end_parallel_block(code)
8110             code.end_block() # pragma omp parallel end block
8111
8112
8113 class CnameDecoratorNode(StatNode):
8114     """
8115     This node is for the cname decorator in CythonUtilityCode:
8116
8117         @cname('the_cname')
8118         cdef func(...):
8119             ...
8120
8121     In case of a cdef class the cname specifies the objstruct_cname.
8122
8123     node        the node to which the cname decorator is applied
8124     cname       the cname the node should get
8125     """
8126
8127     child_attrs = ['node']
8128
8129     def analyse_declarations(self, env):
8130         self.node.analyse_declarations(env)
8131
8132         node = self.node
8133         if isinstance(node, CompilerDirectivesNode):
8134             node = node.body.stats[0]
8135
8136         self.is_function = isinstance(node, FuncDefNode)
8137         is_struct_or_enum = isinstance(node, (CStructOrUnionDefNode,
8138                                                    CEnumDefNode))
8139         e = node.entry
8140
8141         if self.is_function:
8142             e.cname = self.cname
8143             e.func_cname = self.cname
8144             e.used = True
8145             if e.pyfunc_cname and '.' in e.pyfunc_cname:
8146                 e.pyfunc_cname = self.mangle(e.pyfunc_cname)
8147         elif is_struct_or_enum:
8148             e.cname = e.type.cname = self.cname
8149         else:
8150             scope = node.scope
8151
8152             e.cname = self.cname
8153             e.type.objstruct_cname = self.cname + '_obj'
8154             e.type.typeobj_cname = Naming.typeobj_prefix + self.cname
8155             e.type.typeptr_cname = self.cname + '_type'
8156             e.type.scope.namespace_cname = e.type.typeptr_cname
8157
8158             e.as_variable.cname = py_object_type.cast_code(e.type.typeptr_cname)
8159
8160             scope.scope_prefix = self.cname + "_"
8161
8162             for name, entry in scope.entries.iteritems():
8163                 if entry.func_cname:
8164                     entry.func_cname = self.mangle(entry.cname)
8165                 if entry.pyfunc_cname:
8166                     entry.pyfunc_cname = self.mangle(entry.pyfunc_cname)
8167
8168     def mangle(self, cname):
8169         if '.' in cname:
8170             # remove __pyx_base from func_cname
8171             cname = cname.split('.')[-1]
8172         return '%s_%s' % (self.cname, cname)
8173
8174     def analyse_expressions(self, env):
8175         self.node = self.node.analyse_expressions(env)
8176         return self
8177
8178     def generate_function_definitions(self, env, code):
8179         "Ensure a prototype for every @cname method in the right place"
8180         if self.is_function and env.is_c_class_scope:
8181             # method in cdef class, generate a prototype in the header
8182             h_code = code.globalstate['utility_code_proto']
8183
8184             if isinstance(self.node, DefNode):
8185                 self.node.generate_function_header(
8186                             h_code, with_pymethdef=False, proto_only=True)
8187             else:
8188                 import ModuleNode
8189                 entry = self.node.entry
8190                 cname = entry.cname
8191                 entry.cname = entry.func_cname
8192
8193                 ModuleNode.generate_cfunction_declaration(
8194                         entry,
8195                         env.global_scope(),
8196                         h_code,
8197                         definition=True)
8198
8199                 entry.cname = cname
8200
8201         self.node.generate_function_definitions(env, code)
8202
8203     def generate_execution_code(self, code):
8204         self.node.generate_execution_code(code)
8205
8206
8207 #------------------------------------------------------------------------------------
8208 #
8209 #  Runtime support code
8210 #
8211 #------------------------------------------------------------------------------------
8212
8213 if Options.gcc_branch_hints:
8214     branch_prediction_macros = """
8215 /* Test for GCC > 2.95 */
8216 #if defined(__GNUC__) \
8217     && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))
8218   #define likely(x)   __builtin_expect(!!(x), 1)
8219   #define unlikely(x) __builtin_expect(!!(x), 0)
8220 #else /* !__GNUC__ or GCC < 2.95 */
8221   #define likely(x)   (x)
8222   #define unlikely(x) (x)
8223 #endif /* __GNUC__ */
8224 """
8225 else:
8226     branch_prediction_macros = """
8227 #define likely(x)   (x)
8228 #define unlikely(x) (x)
8229 """
8230
8231 #------------------------------------------------------------------------------------
8232
8233 printing_utility_code = UtilityCode.load_cached("Print", "Printing.c")
8234 printing_one_utility_code = UtilityCode.load_cached("PrintOne", "Printing.c")
8235
8236 #------------------------------------------------------------------------------------
8237
8238 # Exception raising code
8239 #
8240 # Exceptions are raised by __Pyx_Raise() and stored as plain
8241 # type/value/tb in PyThreadState->curexc_*.  When being caught by an
8242 # 'except' statement, curexc_* is moved over to exc_* by
8243 # __Pyx_GetException()
8244
8245 restore_exception_utility_code = UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")
8246 raise_utility_code = UtilityCode.load_cached("RaiseException", "Exceptions.c")
8247 get_exception_utility_code = UtilityCode.load_cached("GetException", "Exceptions.c")
8248 swap_exception_utility_code = UtilityCode.load_cached("SwapException", "Exceptions.c")
8249 reset_exception_utility_code = UtilityCode.load_cached("SaveResetException", "Exceptions.c")
8250 traceback_utility_code = UtilityCode.load_cached("AddTraceback", "Exceptions.c")
8251
8252 #------------------------------------------------------------------------------------
8253
8254 get_exception_tuple_utility_code = UtilityCode(proto="""
8255 static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
8256 """,
8257 # I doubt that calling __Pyx_GetException() here is correct as it moves
8258 # the exception from tstate->curexc_* to tstate->exc_*, which prevents
8259 # exception handlers later on from receiving it.
8260 impl = """
8261 static PyObject *__Pyx_GetExceptionTuple(void) {
8262     PyObject *type = NULL, *value = NULL, *tb = NULL;
8263     if (__Pyx_GetException(&type, &value, &tb) == 0) {
8264         PyObject* exc_info = PyTuple_New(3);
8265         if (exc_info) {
8266             Py_INCREF(type);
8267             Py_INCREF(value);
8268             Py_INCREF(tb);
8269             PyTuple_SET_ITEM(exc_info, 0, type);
8270             PyTuple_SET_ITEM(exc_info, 1, value);
8271             PyTuple_SET_ITEM(exc_info, 2, tb);
8272             return exc_info;
8273         }
8274     }
8275     return NULL;
8276 }
8277 """,
8278 requires=[get_exception_utility_code])