Home | History | Annotate | Download | only in Compiler
      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])
   8279