Nodes.py 319 KB
Newer Older
William Stein's avatar
William Stein committed
1
#
2
#   Parse tree nodes
William Stein's avatar
William Stein committed
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 11
               CppClassScope=object, UtilityCode=object, EncodedString=object,
               absolute_path_length=cython.Py_ssize_t)
William Stein's avatar
William Stein committed
12

13
import sys, os, copy
Robert Bradshaw's avatar
Robert Bradshaw committed
14

15
import Builtin
16
from Errors import error, warning, InternalError, CompileError
William Stein's avatar
William Stein committed
17 18
import Naming
import PyrexTypes
19
import TypeSlots
20
from PyrexTypes import py_object_type, error_type
Stefan Behnel's avatar
Stefan Behnel committed
21
from Symtab import ModuleScope, LocalScope, ClosureScope, \
22 23
    StructOrUnionScope, PyClassScope, CppClassScope
from Code import UtilityCode
24
from StringEncoding import EncodedString, escape_byte_string, split_string_literal
William Stein's avatar
William Stein committed
25
import Options
26
import DebugFlags
27
from Cython.Compiler import Errors
28
from itertools import chain
William Stein's avatar
William Stein committed
29

Gary Furnish's avatar
Gary Furnish committed
30
absolute_path_length = 0
31 32 33 34 35 36 37

def relative_position(pos):
    """
    We embed the relative filename in the generated C file, since we
    don't want to have to regnerate and compile all the source code
    whenever the Python install directory moves (which could happen,
    e.g,. when distributing binaries.)
38

39 40 41 42 43 44 45 46 47
    INPUT:
        a position tuple -- (absolute filename, line number column position)

    OUTPUT:
        relative filename
        line number

    AUTHOR: William Stein
    """
Gary Furnish's avatar
Gary Furnish committed
48 49
    global absolute_path_length
    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 54 55

def embed_position(pos, docstring):
    if not Options.embed_pos_in_docstring:
        return docstring
56
    pos_line = u'File: %s (starting at line %s)' % relative_position(pos)
57 58
    if docstring is None:
        # unicode string
59
        return EncodedString(pos_line)
60 61 62 63 64 65 66 67 68 69 70 71

    # make sure we can encode the filename in the docstring encoding
    # otherwise make the docstring a unicode string
    encoding = docstring.encoding
    if encoding is not None:
        try:
            encoded_bytes = pos_line.encode(encoding)
        except UnicodeEncodeError:
            encoding = None

    if not docstring:
        # reuse the string encoding of the original docstring
72
        doc = EncodedString(pos_line)
73
    else:
74
        doc = EncodedString(pos_line + u'\n' + docstring)
75 76
    doc.encoding = encoding
    return doc
77

78 79 80 81 82 83 84

from Code import CCodeWriter
from types import FunctionType

def write_func_call(func):
    def f(*args, **kwds):
        if len(args) > 1 and isinstance(args[1], CCodeWriter):
Robert Bradshaw's avatar
Robert Bradshaw committed
85 86
            # here we annotate the code with this function call
            # but only if new code is generated
87
            node, code = args[:2]
Robert Bradshaw's avatar
Robert Bradshaw committed
88 89
            marker = '                    /* %s -> %s.%s %s */' % (
                    ' ' * code.call_level,
90 91
                    node.__class__.__name__,
                    func.__name__,
Robert Bradshaw's avatar
Robert Bradshaw committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
                    node.pos[1:])
            pristine = code.buffer.stream.tell()
            code.putln(marker)
            start = code.buffer.stream.tell()
            code.call_level += 4
            res = func(*args, **kwds)
            code.call_level -= 4
            if start == code.buffer.stream.tell():
                code.buffer.stream.seek(pristine)
            else:
                marker = marker.replace('->', '<-')
                code.putln(marker)
            return res
        else:
            return func(*args, **kwds)
107 108 109 110
    return f

class VerboseCodeWriter(type):
    # Set this as a metaclass to trace function calls in code.
111
    # This slows down code generation and makes much larger files.
112 113 114 115 116 117 118 119
    def __new__(cls, name, bases, attrs):
        attrs = dict(attrs)
        for mname, m in attrs.items():
            if isinstance(m, FunctionType):
                attrs[mname] = write_func_call(m)
        return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs)


Stefan Behnel's avatar
Stefan Behnel committed
120
class Node(object):
William Stein's avatar
William Stein committed
121 122 123
    #  pos         (string, int, int)   Source file position
    #  is_name     boolean              Is a NameNode
    #  is_literal  boolean              Is a ConstNode
124

125 126
    if DebugFlags.debug_trace_code_generation:
        __metaclass__ = VerboseCodeWriter
127

William Stein's avatar
William Stein committed
128
    is_name = 0
129
    is_none = 0
130
    is_nonecheck = 0
William Stein's avatar
William Stein committed
131
    is_literal = 0
132
    is_terminator = 0
133
    temps = None
134

135 136 137
    # All descandants should set child_attrs to a list of the attributes
    # containing nodes considered "children" in the tree. Each such attribute
    # can either contain a single node or a list of nodes. See Visitor.py.
138
    child_attrs = None
139

140 141
    cf_state = None

142 143 144 145 146
    # This may be an additional (or 'actual') type that will be checked when
    # this node is coerced to another type. This could be useful to set when
    # the actual type to which it can coerce is known, but you want to leave
    # the type a py_object_type
    coercion_type = None
147

William Stein's avatar
William Stein committed
148 149 150
    def __init__(self, pos, **kw):
        self.pos = pos
        self.__dict__.update(kw)
151

152 153
    gil_message = "Operation"

154
    nogil_check = None
155

156
    def gil_error(self, env=None):
157
        error(self.pos, "%s not allowed without gil" % self.gil_message)
158

Robert Bradshaw's avatar
Robert Bradshaw committed
159
    cpp_message = "Operation"
160

Robert Bradshaw's avatar
Robert Bradshaw committed
161 162 163 164 165 166
    def cpp_check(self, env):
        if not env.is_cpp():
            self.cpp_error()

    def cpp_error(self):
        error(self.pos, "%s only allowed in c++" % self.cpp_message)
167

168 169 170 171 172 173
    def clone_node(self):
        """Clone the node. This is defined as a shallow copy, except for member lists
           amongst the child attributes (from get_child_accessors) which are also
           copied. Lists containing child nodes are thus seen as a way for the node
           to hold multiple children directly; the list is not treated as a seperate
           level in the tree."""
174 175 176
        result = copy.copy(self)
        for attrname in result.child_attrs:
            value = getattr(result, attrname)
177
            if isinstance(value, list):
178
                setattr(result, attrname, [x for x in value])
179
        return result
180 181


William Stein's avatar
William Stein committed
182
    #
183
    #  There are 3 phases of parse tree processing, applied in order to
William Stein's avatar
William Stein committed
184 185
    #  all the statements in a given scope-block:
    #
186
    #  (0) analyse_declarations
William Stein's avatar
William Stein committed
187 188 189 190
    #        Make symbol table entries for all declarations at the current
    #        level, both explicit (def, cdef, etc.) and implicit (assignment
    #        to an otherwise undeclared name).
    #
191
    #  (1) analyse_expressions
William Stein's avatar
William Stein committed
192 193
    #         Determine the result types of expressions and fill in the
    #         'type' attribute of each ExprNode. Insert coercion nodes into the
194
    #         tree where needed to convert to and from Python objects.
William Stein's avatar
William Stein committed
195 196 197 198
    #         Allocate temporary locals for intermediate results. Fill
    #         in the 'result_code' attribute of each ExprNode with a C code
    #         fragment.
    #
199
    #  (2) generate_code
William Stein's avatar
William Stein committed
200 201 202 203
    #         Emit C code for all declarations, statements and expressions.
    #         Recursively applies the 3 processing phases to the bodies of
    #         functions.
    #
204

William Stein's avatar
William Stein committed
205 206
    def analyse_declarations(self, env):
        pass
207

William Stein's avatar
William Stein committed
208 209 210
    def analyse_expressions(self, env):
        raise InternalError("analyse_expressions not implemented for %s" % \
            self.__class__.__name__)
211

William Stein's avatar
William Stein committed
212 213 214
    def generate_code(self, code):
        raise InternalError("generate_code not implemented for %s" % \
            self.__class__.__name__)
215

216 217 218 219
    def annotate(self, code):
        # mro does the wrong thing
        if isinstance(self, BlockNode):
            self.body.annotate(code)
220

221 222 223 224
    def end_pos(self):
        try:
            return self._end_pos
        except AttributeError:
Stefan Behnel's avatar
Stefan Behnel committed
225
            pos = self.pos
226 227 228
            if not self.child_attrs:
                self._end_pos = pos
                return pos
229
            for attr in self.child_attrs:
230
                child = getattr(self, attr)
231
                # Sometimes lists, sometimes nodes
232 233 234
                if child is None:
                    pass
                elif isinstance(child, list):
Stefan Behnel's avatar
Stefan Behnel committed
235 236
                    for c in child:
                        pos = max(pos, c.end_pos())
237
                else:
Stefan Behnel's avatar
Stefan Behnel committed
238 239 240
                    pos = max(pos, child.end_pos())
            self._end_pos = pos
            return pos
William Stein's avatar
William Stein committed
241

242
    def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None):
243 244
        if cutoff == 0:
            return "<...nesting level cutoff...>"
245 246 247
        if encountered is None:
            encountered = set()
        if id(self) in encountered:
248
            return "<%s (0x%x) -- already output>" % (self.__class__.__name__, id(self))
249
        encountered.add(id(self))
250

251 252
        def dump_child(x, level):
            if isinstance(x, Node):
253
                return x.dump(level, filter_out, cutoff-1, encountered)
254
            elif isinstance(x, list):
Robert Bradshaw's avatar
Robert Bradshaw committed
255
                return "[%s]" % ", ".join([dump_child(item, level) for item in x])
256 257
            else:
                return repr(x)
258 259


260
        attrs = [(key, value) for key, value in self.__dict__.items() if key not in filter_out]
261
        if len(attrs) == 0:
262
            return "<%s (0x%x)>" % (self.__class__.__name__, id(self))
263 264
        else:
            indent = "  " * level
265
            res = "<%s (0x%x)\n" % (self.__class__.__name__, id(self))
266 267 268 269
            for key, value in attrs:
                res += "%s  %s: %s\n" % (indent, key, dump_child(value, level + 1))
            res += "%s>" % indent
            return res
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

class CompilerDirectivesNode(Node):
    """
    Sets compiler directives for the children nodes
    """
    #  directives     {string:value}  A dictionary holding the right value for
    #                                 *all* possible directives.
    #  body           Node
    child_attrs = ["body"]

    def analyse_declarations(self, env):
        old = env.directives
        env.directives = self.directives
        self.body.analyse_declarations(env)
        env.directives = old
285

286 287 288 289 290 291 292 293 294 295 296 297 298
    def analyse_expressions(self, env):
        old = env.directives
        env.directives = self.directives
        self.body.analyse_expressions(env)
        env.directives = old

    def generate_function_definitions(self, env, code):
        env_old = env.directives
        code_old = code.globalstate.directives
        code.globalstate.directives = self.directives
        self.body.generate_function_definitions(env, code)
        env.directives = env_old
        code.globalstate.directives = code_old
299

300 301 302 303 304
    def generate_execution_code(self, code):
        old = code.globalstate.directives
        code.globalstate.directives = self.directives
        self.body.generate_execution_code(code)
        code.globalstate.directives = old
305

306 307 308 309 310
    def annotate(self, code):
        old = code.globalstate.directives
        code.globalstate.directives = self.directives
        self.body.annotate(code)
        code.globalstate.directives = old
311

Stefan Behnel's avatar
Stefan Behnel committed
312
class BlockNode(object):
William Stein's avatar
William Stein committed
313 314
    #  Mixin class for nodes representing a declaration block.

315
    def generate_cached_builtins_decls(self, env, code):
316
        entries = env.global_scope().undeclared_cached_builtins
317
        for entry in entries:
318
            code.globalstate.add_cached_builtin_decl(entry)
319
        del entries[:]
320 321 322 323

    def generate_lambda_definitions(self, env, code):
        for node in env.lambda_defs:
            node.generate_function_definitions(env, code)
William Stein's avatar
William Stein committed
324 325 326

class StatListNode(Node):
    # stats     a list of StatNode
327

328
    child_attrs = ["stats"]
329 330 331 332 333

    def create_analysed(pos, env, *args, **kw):
        node = StatListNode(pos, *args, **kw)
        return node # No node-specific analysis necesarry
    create_analysed = staticmethod(create_analysed)
334

William Stein's avatar
William Stein committed
335 336 337 338
    def analyse_declarations(self, env):
        #print "StatListNode.analyse_declarations" ###
        for stat in self.stats:
            stat.analyse_declarations(env)
339

William Stein's avatar
William Stein committed
340 341 342 343
    def analyse_expressions(self, env):
        #print "StatListNode.analyse_expressions" ###
        for stat in self.stats:
            stat.analyse_expressions(env)
344

345
    def generate_function_definitions(self, env, code):
William Stein's avatar
William Stein committed
346 347
        #print "StatListNode.generate_function_definitions" ###
        for stat in self.stats:
348
            stat.generate_function_definitions(env, code)
349

William Stein's avatar
William Stein committed
350 351 352 353 354
    def generate_execution_code(self, code):
        #print "StatListNode.generate_execution_code" ###
        for stat in self.stats:
            code.mark_pos(stat.pos)
            stat.generate_execution_code(code)
355

356 357 358
    def annotate(self, code):
        for stat in self.stats:
            stat.annotate(code)
359

William Stein's avatar
William Stein committed
360 361 362 363 364 365 366 367 368 369 370 371 372

class StatNode(Node):
    #
    #  Code generation for statements is split into the following subphases:
    #
    #  (1) generate_function_definitions
    #        Emit C code for the definitions of any structs,
    #        unions, enums and functions defined in the current
    #        scope-block.
    #
    #  (2) generate_execution_code
    #        Emit C code for executable statements.
    #
373

374
    def generate_function_definitions(self, env, code):
William Stein's avatar
William Stein committed
375
        pass
376

William Stein's avatar
William Stein committed
377 378 379 380 381 382 383 384
    def generate_execution_code(self, code):
        raise InternalError("generate_execution_code not implemented for %s" % \
            self.__class__.__name__)


class CDefExternNode(StatNode):
    #  include_file   string or None
    #  body           StatNode
385

386
    child_attrs = ["body"]
387

William Stein's avatar
William Stein committed
388 389 390 391 392 393 394
    def analyse_declarations(self, env):
        if self.include_file:
            env.add_include_file(self.include_file)
        old_cinclude_flag = env.in_cinclude
        env.in_cinclude = 1
        self.body.analyse_declarations(env)
        env.in_cinclude = old_cinclude_flag
395

William Stein's avatar
William Stein committed
396 397
    def analyse_expressions(self, env):
        pass
398

William Stein's avatar
William Stein committed
399 400
    def generate_execution_code(self, code):
        pass
401 402 403

    def annotate(self, code):
        self.body.annotate(code)
404

William Stein's avatar
William Stein committed
405 406 407 408 409 410 411 412

class CDeclaratorNode(Node):
    # Part of a C declaration.
    #
    # Processing during analyse_declarations phase:
    #
    #   analyse
    #      Returns (name, type) pair where name is the
413
    #      CNameDeclaratorNode of the name being declared
William Stein's avatar
William Stein committed
414 415
    #      and type is the type it is being declared as.
    #
416
    #  calling_convention  string   Calling convention of CFuncDeclaratorNode
417
    #                               for which this is a base
418

419 420
    child_attrs = []

421 422
    calling_convention = ""

William Stein's avatar
William Stein committed
423 424

class CNameDeclaratorNode(CDeclaratorNode):
425
    #  name    string             The Cython name being declared
Robert Bradshaw's avatar
Robert Bradshaw committed
426 427
    #  cname   string or None     C name, if specified
    #  default ExprNode or None   the value assigned on declaration
428

Robert Bradshaw's avatar
Robert Bradshaw committed
429
    child_attrs = ['default']
430

431
    default = None
432

433 434
    def analyse(self, base_type, env, nonempty = 0):
        if nonempty and self.name == '':
435
            # May have mistaken the name for the type.
436
            if base_type.is_ptr or base_type.is_array or base_type.is_buffer:
437
                error(self.pos, "Missing argument name")
438 439
            elif base_type.is_void:
                error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
440 441 442
            else:
                self.name = base_type.declaration_code("", for_display=1, pyrex=1)
                base_type = py_object_type
443 444 445 446

        if base_type.is_fused and env.fused_to_specific:
            base_type = base_type.specialize(env.fused_to_specific)

447
        self.type = base_type
William Stein's avatar
William Stein committed
448
        return self, base_type
449

William Stein's avatar
William Stein committed
450 451
class CPtrDeclaratorNode(CDeclaratorNode):
    # base     CDeclaratorNode
452

453 454
    child_attrs = ["base"]

455
    def analyse(self, base_type, env, nonempty = 0):
William Stein's avatar
William Stein committed
456 457 458 459
        if base_type.is_pyobject:
            error(self.pos,
                "Pointer base type cannot be a Python object")
        ptr_type = PyrexTypes.c_ptr_type(base_type)
460
        return self.base.analyse(ptr_type, env, nonempty = nonempty)
Danilo Freitas's avatar
Danilo Freitas committed
461 462 463 464 465 466 467 468 469 470

class CReferenceDeclaratorNode(CDeclaratorNode):
    # base     CDeclaratorNode

    child_attrs = ["base"]

    def analyse(self, base_type, env, nonempty = 0):
        if base_type.is_pyobject:
            error(self.pos,
                  "Reference base type cannot be a Python object")
471
        ref_type = PyrexTypes.c_ref_type(base_type)
Danilo Freitas's avatar
Danilo Freitas committed
472 473
        return self.base.analyse(ref_type, env, nonempty = nonempty)

William Stein's avatar
William Stein committed
474 475 476
class CArrayDeclaratorNode(CDeclaratorNode):
    # base        CDeclaratorNode
    # dimension   ExprNode
477 478

    child_attrs = ["base", "dimension"]
479

480
    def analyse(self, base_type, env, nonempty = 0):
Robert Bradshaw's avatar
Robert Bradshaw committed
481 482 483 484 485 486 487 488 489 490 491 492 493
        if base_type.is_cpp_class:
            from ExprNodes import TupleNode
            if isinstance(self.dimension, TupleNode):
                args = self.dimension.args
            else:
                args = self.dimension,
            values = [v.analyse_as_type(env) for v in args]
            if None in values:
                ix = values.index(None)
                error(args[ix].pos, "Template parameter not a type.")
                return error_type
            base_type = base_type.specialize_here(self.pos, values)
            return self.base.analyse(base_type, env, nonempty = nonempty)
William Stein's avatar
William Stein committed
494 495 496 497
        if self.dimension:
            self.dimension.analyse_const_expression(env)
            if not self.dimension.type.is_int:
                error(self.dimension.pos, "Array dimension not integer")
498 499 500 501 502 503 504
            size = self.dimension.get_constant_c_result_code()
            if size is not None:
                try:
                    size = int(size)
                except ValueError:
                    # runtime constant?
                    pass
William Stein's avatar
William Stein committed
505 506 507 508 509 510 511 512
        else:
            size = None
        if not base_type.is_complete():
            error(self.pos,
                "Array element type '%s' is incomplete" % base_type)
        if base_type.is_pyobject:
            error(self.pos,
                "Array element cannot be a Python object")
513 514 515
        if base_type.is_cfunction:
            error(self.pos,
                "Array element cannot be a function")
William Stein's avatar
William Stein committed
516
        array_type = PyrexTypes.c_array_type(base_type, size)
517
        return self.base.analyse(array_type, env, nonempty = nonempty)
William Stein's avatar
William Stein committed
518 519 520 521 522 523 524 525


class CFuncDeclaratorNode(CDeclaratorNode):
    # base             CDeclaratorNode
    # args             [CArgDeclNode]
    # has_varargs      boolean
    # exception_value  ConstNode
    # exception_check  boolean    True if PyErr_Occurred check needed
526 527
    # nogil            boolean    Can be called without gil
    # with_gil         boolean    Acquire gil around function body
528

529 530
    child_attrs = ["base", "args", "exception_value"]

531
    overridable = 0
532
    optional_arg_count = 0
William Stein's avatar
William Stein committed
533

534
    def analyse(self, return_type, env, nonempty = 0, directive_locals = {}):
535 536
        if nonempty:
            nonempty -= 1
William Stein's avatar
William Stein committed
537
        func_type_args = []
538 539 540
        for i, arg_node in enumerate(self.args):
            name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
                                                     is_self_arg = (i == 0 and env.is_c_class_scope))
William Stein's avatar
William Stein committed
541
            name = name_declarator.name
542 543 544 545 546
            if name in directive_locals:
                type_node = directive_locals[name]
                other_type = type_node.analyse_as_type(env)
                if other_type is None:
                    error(type_node.pos, "Not a type")
Robert Bradshaw's avatar
Robert Bradshaw committed
547
                elif (type is not PyrexTypes.py_object_type
548 549 550 551 552
                      and not type.same_as(other_type)):
                    error(self.base.pos, "Signature does not agree with previous declaration")
                    error(type_node.pos, "Previous declaration here")
                else:
                    type = other_type
William Stein's avatar
William Stein committed
553
            if name_declarator.cname:
554
                error(self.pos,
William Stein's avatar
William Stein committed
555
                    "Function argument cannot have C name specification")
556 557 558
            if i==0 and env.is_c_class_scope and type.is_unspecified:
                # fix the type of self
                type = env.parent_type
William Stein's avatar
William Stein committed
559 560 561 562 563
            # Turn *[] argument into **
            if type.is_array:
                type = PyrexTypes.c_ptr_type(type.base_type)
            # Catch attempted C-style func(void) decl
            if type.is_void:
Robert Bradshaw's avatar
Robert Bradshaw committed
564
                error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
William Stein's avatar
William Stein committed
565 566 567
            func_type_args.append(
                PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
            if arg_node.default:
568
                self.optional_arg_count += 1
569 570
            elif self.optional_arg_count:
                error(self.pos, "Non-default argument follows default argument")
571

William Stein's avatar
William Stein committed
572 573
        exc_val = None
        exc_check = 0
574
        if self.exception_check == '+':
575
            env.add_include_file('ios')         # for std::ios_base::failure
576
            env.add_include_file('new')         # for std::bad_alloc
577
            env.add_include_file('stdexcept')
578
            env.add_include_file('typeinfo')    # for std::bad_cast
William Stein's avatar
William Stein committed
579
        if return_type.is_pyobject \
Robert Bradshaw's avatar
Robert Bradshaw committed
580 581
            and (self.exception_value or self.exception_check) \
            and self.exception_check != '+':
William Stein's avatar
William Stein committed
582 583 584 585 586
                error(self.pos,
                    "Exception clause not allowed for function returning Python object")
        else:
            if self.exception_value:
                self.exception_value.analyse_const_expression(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
587
                if self.exception_check == '+':
588
                    self.exception_value.analyse_types(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
589 590 591 592 593 594
                    exc_val_type = self.exception_value.type
                    if not exc_val_type.is_error and \
                          not exc_val_type.is_pyobject and \
                          not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
                        error(self.exception_value.pos,
                            "Exception value must be a Python exception or cdef function with no arguments.")
595
                    exc_val = self.exception_value
Robert Bradshaw's avatar
Robert Bradshaw committed
596
                else:
597
                    self.exception_value = self.exception_value.coerce_to(return_type, env)
598 599 600 601 602 603 604 605
                    if self.exception_value.analyse_const_expression(env):
                        exc_val = self.exception_value.get_constant_c_result_code()
                        if exc_val is None:
                            raise InternalError("get_constant_c_result_code not implemented for %s" %
                                self.exception_value.__class__.__name__)
                        if not return_type.assignable_from(self.exception_value.type):
                            error(self.exception_value.pos,
                                  "Exception value incompatible with function return type")
William Stein's avatar
William Stein committed
606
            exc_check = self.exception_check
607 608 609
        if return_type.is_cfunction:
            error(self.pos,
                "Function cannot return a function")
William Stein's avatar
William Stein committed
610
        func_type = PyrexTypes.CFuncType(
611
            return_type, func_type_args, self.has_varargs,
612
            optional_arg_count = self.optional_arg_count,
613
            exception_value = exc_val, exception_check = exc_check,
614
            calling_convention = self.base.calling_convention,
615
            nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
616

617
        if self.optional_arg_count:
618 619 620 621 622 623 624 625 626 627 628
            if func_type.is_fused:
                # This is a bit of a hack... When we need to create specialized CFuncTypes
                # on the fly because the cdef is defined in a pxd, we need to declare the specialized optional arg
                # struct
                def declare_opt_arg_struct(func_type, fused_cname):
                    self.declare_optional_arg_struct(func_type, env, fused_cname)

                func_type.declare_opt_arg_struct = declare_opt_arg_struct
            else:
                self.declare_optional_arg_struct(func_type, env)

629 630 631 632 633 634 635
        callspec = env.directives['callspec']
        if callspec:
            current = func_type.calling_convention
            if current and current != callspec:
                error(self.pos, "cannot have both '%s' and '%s' "
                      "calling conventions" % (current, callspec))
            func_type.calling_convention = callspec
William Stein's avatar
William Stein committed
636 637
        return self.base.analyse(func_type, env)

638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
    def declare_optional_arg_struct(self, func_type, env, fused_cname=None):
        """
        Declares the optional argument struct (the struct used to hold the
        values for optional arguments). For fused cdef functions, this is
        deferred as analyse_declarations is called only once (on the fused
        cdef function).
        """
        scope = StructOrUnionScope()
        arg_count_member = '%sn' % Naming.pyrex_prefix
        scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)

        for arg in func_type.args[len(func_type.args)-self.optional_arg_count:]:
            scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)

        struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)

        if fused_cname is not None:
            struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname)

        op_args_struct = env.global_scope().declare_struct_or_union(
                name = struct_cname,
                kind = 'struct',
                scope = scope,
                typedef_flag = 0,
                pos = self.pos,
                cname = struct_cname)

        op_args_struct.defined_in_pxd = 1
        op_args_struct.used = 1

        func_type.op_arg_struct = PyrexTypes.c_ptr_type(op_args_struct.type)

William Stein's avatar
William Stein committed
670 671 672 673 674 675 676

class CArgDeclNode(Node):
    # Item in a function declaration argument list.
    #
    # base_type      CBaseTypeNode
    # declarator     CDeclaratorNode
    # not_none       boolean            Tagged with 'not None'
677 678
    # or_none        boolean            Tagged with 'or None'
    # accept_none    boolean            Resolved boolean for not_none/or_none
William Stein's avatar
William Stein committed
679
    # default        ExprNode or None
680
    # default_value  PyObjectConst      constant for default value
681
    # annotation     ExprNode or None   Py3 function arg annotation
William Stein's avatar
William Stein committed
682
    # is_self_arg    boolean            Is the "self" arg of an extension type method
683
    # is_type_arg    boolean            Is the "class" arg of an extension type classmethod
684
    # is_kw_only     boolean            Is a keyword-only argument
685
    # is_dynamic     boolean            Non-literal arg stored inside CyFunction
686

687 688
    child_attrs = ["base_type", "declarator", "default"]

William Stein's avatar
William Stein committed
689
    is_self_arg = 0
690
    is_type_arg = 0
691
    is_generic = 1
692 693 694
    kw_only = 0
    not_none = 0
    or_none = 0
695 696
    type = None
    name_declarator = None
697
    default_value = None
698
    annotation = None
699
    is_dynamic = 0
700

701 702 703
    def analyse(self, env, nonempty = 0, is_self_arg = False):
        if is_self_arg:
            self.base_type.is_self_arg = self.is_self_arg = True
704 705 706 707 708
        if self.type is None:
            # The parser may missinterpret names as types...
            # We fix that here.
            if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
                if nonempty:
709 710 711 712 713 714 715
                    if self.base_type.is_basic_c_type:
                        # char, short, long called "int"
                        type = self.base_type.analyse(env, could_be_name = True)
                        arg_name = type.declaration_code("")
                    else:
                        arg_name = self.base_type.name
                    self.declarator.name = EncodedString(arg_name)
716 717 718 719 720
                    self.base_type.name = None
                    self.base_type.is_basic_c_type = False
                could_be_name = True
            else:
                could_be_name = False
721
            self.base_type.is_arg = True
722
            base_type = self.base_type.analyse(env, could_be_name = could_be_name)
Robert Bradshaw's avatar
Robert Bradshaw committed
723
            if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
724
                self.declarator.name = self.base_type.arg_name
725 726
            # The parser is unable to resolve the ambiguity of [] as part of the
            # type (e.g. in buffers) or empty declarator (as with arrays).
727
            # This is only arises for empty multi-dimensional arrays.
728 729
            if (base_type.is_array
                    and isinstance(self.base_type, TemplatedTypeNode)
730 731 732 733 734 735
                    and isinstance(self.declarator, CArrayDeclaratorNode)):
                declarator = self.declarator
                while isinstance(declarator.base, CArrayDeclaratorNode):
                    declarator = declarator.base
                declarator.base = self.base_type.array_declarator
                base_type = base_type.base_type
736
            return self.declarator.analyse(base_type, env, nonempty = nonempty)
737
        else:
738
            return self.name_declarator, self.type
William Stein's avatar
William Stein committed
739

740 741 742 743 744 745 746 747 748
    def calculate_default_value_code(self, code):
        if self.default_value is None:
            if self.default:
                if self.default.is_literal:
                    # will not output any code, just assign the result_code
                    self.default.generate_evaluation_code(code)
                    return self.type.cast_code(self.default.result())
                self.default_value = code.get_argument_default_const(self.type)
        return self.default_value
749

750 751 752 753
    def annotate(self, code):
        if self.default:
            self.default.annotate(code)

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
    def generate_assignment_code(self, code, target=None):
        default = self.default
        if default is None or default.is_literal:
            return
        if target is None:
            target = self.calculate_default_value_code(code)
        default.generate_evaluation_code(code)
        default.make_owned_reference(code)
        result = default.result_as(self.type)
        code.putln("%s = %s;" % (target, result))
        if self.type.is_pyobject:
            code.put_giveref(default.result())
        default.generate_post_assignment_code(code)
        default.free_temps(code)

William Stein's avatar
William Stein committed
769 770 771 772 773 774 775 776

class CBaseTypeNode(Node):
    # Abstract base class for C base type nodes.
    #
    # Processing during analyse_declarations phase:
    #
    #   analyse
    #     Returns the type.
777

William Stein's avatar
William Stein committed
778
    pass
779

780 781
    def analyse_as_type(self, env):
        return self.analyse(env)
782

783 784
class CAnalysedBaseTypeNode(Node):
    # type            type
785

786
    child_attrs = []
787

788 789
    def analyse(self, env, could_be_name = False):
        return self.type
William Stein's avatar
William Stein committed
790 791 792 793 794 795 796

class CSimpleBaseTypeNode(CBaseTypeNode):
    # name             string
    # module_path      [string]     Qualifying name components
    # is_basic_c_type  boolean
    # signed           boolean
    # longness         integer
797
    # complex          boolean
William Stein's avatar
William Stein committed
798
    # is_self_arg      boolean      Is self argument of C method
799
    # ##is_type_arg      boolean      Is type argument of class method
William Stein's avatar
William Stein committed
800

801
    child_attrs = []
802
    arg_name = None   # in case the argument name was interpreted as a type
803 804 805
    module_path = []
    is_basic_c_type = False
    complex = False
806

807
    def analyse(self, env, could_be_name = False):
William Stein's avatar
William Stein committed
808
        # Return type descriptor.
809
        #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
William Stein's avatar
William Stein committed
810 811 812 813 814 815 816 817 818
        type = None
        if self.is_basic_c_type:
            type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
            if not type:
                error(self.pos, "Unrecognised type modifier combination")
        elif self.name == "object" and not self.module_path:
            type = py_object_type
        elif self.name is None:
            if self.is_self_arg and env.is_c_class_scope:
819
                #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
William Stein's avatar
William Stein committed
820
                type = env.parent_type
821 822
            ## elif self.is_type_arg and env.is_c_class_scope:
            ##     type = Builtin.type_type
William Stein's avatar
William Stein committed
823 824 825
            else:
                type = py_object_type
        else:
826
            if self.module_path:
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
                # Maybe it's a nested C++ class.
                scope = env
                for item in self.module_path:
                    entry = scope.lookup(item)
                    if entry.is_cpp_class:
                        scope = entry.type.scope
                    else:
                        scope = None
                        break
                
                if scope is None:
                    # Maybe it's a cimport.
                    scope = env.find_imported_module(self.module_path, self.pos)
                    if scope:
                        scope.fused_to_specific = env.fused_to_specific
842 843
            else:
                scope = env
844

William Stein's avatar
William Stein committed
845
            if scope:
846 847
                if scope.is_c_class_scope:
                    scope = scope.global_scope()
848 849 850 851

                type = scope.lookup_type(self.name)
                if type is not None:
                    pass
852 853 854
                elif could_be_name:
                    if self.is_self_arg and env.is_c_class_scope:
                        type = env.parent_type
855 856
                    ## elif self.is_type_arg and env.is_c_class_scope:
                    ##     type = Builtin.type_type
857 858
                    else:
                        type = py_object_type
859
                    self.arg_name = EncodedString(self.name)
William Stein's avatar
William Stein committed
860
                else:
Danilo Freitas's avatar
Danilo Freitas committed
861 862 863
                    if self.templates:
                        if not self.name in self.templates:
                            error(self.pos, "'%s' is not a type identifier" % self.name)
864
                        type = PyrexTypes.TemplatePlaceholderType(self.name)
Danilo Freitas's avatar
Danilo Freitas committed
865 866
                    else:
                        error(self.pos, "'%s' is not a type identifier" % self.name)
867
        if self.complex:
868 869 870
            if not type.is_numeric or type.is_complex:
                error(self.pos, "can only complexify c numeric types")
            type = PyrexTypes.CComplexType(type)
871
            type.create_declaration_utility_code(env)
872 873 874 875 876 877 878 879
        elif type is Builtin.complex_type:
            # Special case: optimise builtin complex type into C's
            # double complex.  The parser cannot do this (as for the
            # normal scalar types) as the user may have redeclared the
            # 'complex' type.  Testing for the exact type here works.
            type = PyrexTypes.c_double_complex_type
            type.create_declaration_utility_code(env)
            self.complex = True
William Stein's avatar
William Stein committed
880 881 882 883 884
        if type:
            return type
        else:
            return PyrexTypes.error_type

885
class MemoryViewSliceTypeNode(CBaseTypeNode):
886

887
    name = 'memoryview'
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
    child_attrs = ['base_type_node', 'axes']

    def analyse(self, env, could_be_name = False):

        base_type = self.base_type_node.analyse(env)
        if base_type.is_error: return base_type

        import MemoryView

        try:
            axes_specs = MemoryView.get_axes_specs(env, self.axes)
        except CompileError, e:
            error(e.position, e.message_only)
            self.type = PyrexTypes.ErrorType()
            return self.type

904 905 906 907 908 909
        if not MemoryView.validate_axes(self.pos, axes_specs):
            self.type = error_type
        else:
            MemoryView.validate_memslice_dtype(self.pos, base_type)
            self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs)
            self.use_memview_utilities(env)
910

911
        return self.type
912

913 914 915 916 917
    def use_memview_utilities(self, env):
        import MemoryView
        env.use_utility_code(MemoryView.view_utility_code)


Robert Bradshaw's avatar
Robert Bradshaw committed
918
class CNestedBaseTypeNode(CBaseTypeNode):
919
    # For C++ classes that live inside other C++ classes.
Robert Bradshaw's avatar
Robert Bradshaw committed
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936

    # name             string
    # base_type        CBaseTypeNode
    child_attrs = ['base_type']
    def analyse(self, env, could_be_name = None):
        base_type = self.base_type.analyse(env)
        if base_type is PyrexTypes.error_type:
            return PyrexTypes.error_type
        if not base_type.is_cpp_class:
            error(self.pos, "'%s' is not a valid type scope" % base_type)
            return PyrexTypes.error_type
        type_entry = base_type.scope.lookup_here(self.name)
        if not type_entry or not type_entry.is_type:
            error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name))
            return PyrexTypes.error_type
        return type_entry.type

937

Danilo Freitas's avatar
Danilo Freitas committed
938
class TemplatedTypeNode(CBaseTypeNode):
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
939
    #  After parsing:
940 941
    #  positional_args  [ExprNode]        List of positional arguments
    #  keyword_args     DictNode          Keyword arguments
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
942 943 944
    #  base_type_node   CBaseTypeNode

    #  After analysis:
945
    #  type             PyrexTypes.BufferType or PyrexTypes.CppClassType  ...containing the right options
946

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
947

948 949
    child_attrs = ["base_type_node", "positional_args",
                   "keyword_args", "dtype_node"]
950

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
951
    dtype_node = None
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
952 953

    name = None
954

955 956 957
    def analyse(self, env, could_be_name = False, base_type = None):
        if base_type is None:
            base_type = self.base_type_node.analyse(env)
958
        if base_type.is_error: return base_type
959

960
        if base_type.is_cpp_class:
961
            # Templated class
962
            if self.keyword_args and self.keyword_args.key_value_pairs:
963 964 965 966 967
                error(self.pos, "c++ templates cannot take keyword arguments");
                self.type = PyrexTypes.error_type
            else:
                template_types = []
                for template_node in self.positional_args:
968 969 970 971 972
                    type = template_node.analyse_as_type(env)
                    if type is None:
                        error(template_node.pos, "unknown type in template argument")
                        return error_type
                    template_types.append(type)
973
                self.type = base_type.specialize_here(self.pos, template_types)
974

975 976
        elif base_type.is_pyobject:
            # Buffer
977
            import Buffer
978

979 980 981 982 983 984
            options = Buffer.analyse_buffer_options(
                self.pos,
                env,
                self.positional_args,
                self.keyword_args,
                base_type.buffer_defaults)
985

Robert Bradshaw's avatar
Robert Bradshaw committed
986 987 988
            if sys.version_info[0] < 3:
                # Py 2.x enforces byte strings as keyword arguments ...
                options = dict([ (name.encode('ASCII'), value)
989
                                 for name, value in options.items() ])
Stefan Behnel's avatar
Stefan Behnel committed
990

991
            self.type = PyrexTypes.BufferType(base_type, **options)
992

993 994
        else:
            # Array
995
            empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
996 997 998 999
            if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
                error(self.pos, "invalid array declaration")
                self.type = PyrexTypes.error_type
            else:
1000
                # It would be nice to merge this class with CArrayDeclaratorNode,
1001 1002 1003 1004 1005
                # but arrays are part of the declaration, not the type...
                if not self.positional_args:
                    dimension = None
                else:
                    dimension = self.positional_args[0]
1006 1007
                self.array_declarator = CArrayDeclaratorNode(self.pos,
                    base = empty_declarator,
1008 1009
                    dimension = dimension)
                self.type = self.array_declarator.analyse(base_type, env)[1]
1010

1011 1012 1013
        if self.type.is_fused and env.fused_to_specific:
            self.type = self.type.specialize(env.fused_to_specific)

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1014
        return self.type
William Stein's avatar
William Stein committed
1015 1016 1017 1018

class CComplexBaseTypeNode(CBaseTypeNode):
    # base_type   CBaseTypeNode
    # declarator  CDeclaratorNode
1019

1020 1021
    child_attrs = ["base_type", "declarator"]

1022 1023
    def analyse(self, env, could_be_name = False):
        base = self.base_type.analyse(env, could_be_name)
William Stein's avatar
William Stein committed
1024 1025 1026 1027
        _, type = self.declarator.analyse(base, env)
        return type


1028 1029 1030 1031 1032 1033
class FusedTypeNode(CBaseTypeNode):
    """
    Represents a fused type in a ctypedef statement:

        ctypedef cython.fused_type(int, long, long long) integral

Mark Florisson's avatar
Mark Florisson committed
1034
    name            str                     name of this fused type
1035 1036 1037 1038 1039
    types           [CSimpleBaseTypeNode]   is the list of types to be fused
    """

    child_attrs = []

Mark Florisson's avatar
Mark Florisson committed
1040 1041 1042 1043 1044 1045 1046
    def analyse_declarations(self, env):
        type = self.analyse(env)
        entry = env.declare_typedef(self.name, type, self.pos)

        # Omit the typedef declaration that self.declarator would produce
        entry.in_cinclude = True

1047
    def analyse(self, env):
Mark Florisson's avatar
Mark Florisson committed
1048 1049 1050
        types = []
        for type_node in self.types:
            type = type_node.analyse_as_type(env)
1051

Mark Florisson's avatar
Mark Florisson committed
1052 1053 1054
            if not type:
                error(type_node.pos, "Not a type")
                continue
1055

Mark Florisson's avatar
Mark Florisson committed
1056
            if type in types:
1057
                error(type_node.pos, "Type specified multiple times")
Mark Florisson's avatar
Mark Florisson committed
1058 1059
            elif type.is_fused:
                error(type_node.pos, "Cannot fuse a fused type")
1060
            else:
Mark Florisson's avatar
Mark Florisson committed
1061
                types.append(type)
1062

1063 1064
        # if len(self.types) == 1:
        #     return types[0]
Mark Florisson's avatar
Mark Florisson committed
1065 1066

        return PyrexTypes.FusedType(types, name=self.name)
1067

1068

William Stein's avatar
William Stein committed
1069 1070 1071 1072 1073 1074
class CVarDefNode(StatNode):
    #  C variable definition or forward/extern function declaration.
    #
    #  visibility    'private' or 'public' or 'extern'
    #  base_type     CBaseTypeNode
    #  declarators   [CDeclaratorNode]
1075
    #  in_pxd        boolean
Stefan Behnel's avatar
Stefan Behnel committed
1076
    #  api           boolean
1077
    #  overridable   boolean        whether it is a cpdef
1078
    #  modifiers     ['inline']
1079

1080
    #  decorators    [cython.locals(...)] or None
1081
    #  directive_locals { string : NameNode } locals defined by cython.locals(...)
1082 1083

    child_attrs = ["base_type", "declarators"]
1084

Robert Bradshaw's avatar
Robert Bradshaw committed
1085
    decorators = None
1086
    directive_locals = None
1087

William Stein's avatar
William Stein committed
1088
    def analyse_declarations(self, env, dest_scope = None):
1089 1090
        if self.directive_locals is None:
            self.directive_locals = {}
William Stein's avatar
William Stein committed
1091 1092
        if not dest_scope:
            dest_scope = env
1093
        self.dest_scope = dest_scope
William Stein's avatar
William Stein committed
1094
        base_type = self.base_type.analyse(env)
1095

1096 1097
        if base_type.is_fused and not self.in_pxd and (env.is_c_class_scope or
                                                       env.is_module_scope):
1098 1099 1100
            error(self.pos, "Fused types not allowed here")
            return error_type

1101
        self.entry = None
1102
        visibility = self.visibility
1103

William Stein's avatar
William Stein committed
1104
        for declarator in self.declarators:
1105 1106 1107 1108
            if isinstance(declarator, CFuncDeclaratorNode):
                name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
            else:
                name_declarator, type = declarator.analyse(base_type, env)
William Stein's avatar
William Stein committed
1109
            if not type.is_complete():
1110
                if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice):
William Stein's avatar
William Stein committed
1111 1112 1113 1114 1115 1116 1117
                    error(declarator.pos,
                        "Variable type '%s' is incomplete" % type)
            if self.visibility == 'extern' and type.is_pyobject:
                error(declarator.pos,
                    "Python object cannot be declared extern")
            name = name_declarator.name
            cname = name_declarator.cname
1118 1119 1120
            if name == '':
                error(declarator.pos, "Missing name in declaration.")
                return
William Stein's avatar
William Stein committed
1121
            if type.is_cfunction:
1122
                self.entry = dest_scope.declare_cfunction(name, type, declarator.pos,
Stefan Behnel's avatar
Stefan Behnel committed
1123
                    cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
1124
                    api = self.api, modifiers = self.modifiers)
1125 1126 1127
                if self.entry is not None:
                    self.entry.is_overridable = self.overridable
                    self.entry.directive_locals = copy.copy(self.directive_locals)
William Stein's avatar
William Stein committed
1128
            else:
1129
                if self.directive_locals:
1130
                    error(self.pos, "Decorators can only be followed by functions")
1131
                self.entry = dest_scope.declare_var(name, type, declarator.pos,
1132 1133
                            cname=cname, visibility=visibility, in_pxd=self.in_pxd,
                            api=self.api, is_cdef=1)
1134

William Stein's avatar
William Stein committed
1135 1136 1137 1138 1139 1140

class CStructOrUnionDefNode(StatNode):
    #  name          string
    #  cname         string or None
    #  kind          "struct" or "union"
    #  typedef_flag  boolean
1141
    #  visibility    "public" or "private"
1142
    #  api           boolean
Stefan Behnel's avatar
Stefan Behnel committed
1143
    #  in_pxd        boolean
William Stein's avatar
William Stein committed
1144 1145
    #  attributes    [CVarDefNode] or None
    #  entry         Entry
1146
    #  packed        boolean
1147

1148
    child_attrs = ["attributes"]
Vitja Makarov's avatar
Vitja Makarov committed
1149

1150 1151
    def declare(self, env, scope=None):
        if self.visibility == 'extern' and self.packed and not scope:
1152
            error(self.pos, "Cannot declare extern struct as 'packed'")
William Stein's avatar
William Stein committed
1153 1154
        self.entry = env.declare_struct_or_union(
            self.name, self.kind, scope, self.typedef_flag, self.pos,
1155 1156
            self.cname, visibility = self.visibility, api = self.api,
            packed = self.packed)
1157 1158 1159 1160 1161 1162

    def analyse_declarations(self, env):
        scope = None
        if self.attributes is not None:
            scope = StructOrUnionScope(self.name)
        self.declare(env, scope)
William Stein's avatar
William Stein committed
1163
        if self.attributes is not None:
Stefan Behnel's avatar
Stefan Behnel committed
1164 1165
            if self.in_pxd and not env.in_cinclude:
                self.entry.defined_in_pxd = 1
William Stein's avatar
William Stein committed
1166 1167
            for attr in self.attributes:
                attr.analyse_declarations(env, scope)
1168 1169 1170 1171
            if self.visibility != 'extern':
                for attr in scope.var_entries:
                    type = attr.type
                    while type.is_array:
1172 1173
                        type = type.base_type
                    if type == self.entry.type:
1174
                        error(attr.pos, "Struct cannot contain itself as a member.")
1175

William Stein's avatar
William Stein committed
1176 1177
    def analyse_expressions(self, env):
        pass
1178

William Stein's avatar
William Stein committed
1179 1180 1181 1182
    def generate_execution_code(self, code):
        pass


1183
class CppClassNode(CStructOrUnionDefNode, BlockNode):
Robert Bradshaw's avatar
Robert Bradshaw committed
1184 1185 1186

    #  name          string
    #  cname         string or None
1187
    #  visibility    "extern"
Robert Bradshaw's avatar
Robert Bradshaw committed
1188 1189 1190
    #  in_pxd        boolean
    #  attributes    [CVarDefNode] or None
    #  entry         Entry
1191
    #  base_classes  [CBaseTypeNode]
Danilo Freitas's avatar
Danilo Freitas committed
1192
    #  templates     [string] or None
Robert Bradshaw's avatar
Robert Bradshaw committed
1193

1194
    def declare(self, env):
1195 1196
        if self.visibility != 'extern' and not env.directives['experimental_cpp_class_def']:
            error(self.pos, "C++ classes need to be declared extern unless experimental_cpp_class_def enabled")
1197 1198 1199 1200 1201 1202 1203 1204
        if self.templates is None:
            template_types = None
        else:
            template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
        self.entry = env.declare_cpp_class(
            self.name, None, self.pos,
            self.cname, base_classes = [], visibility = self.visibility, templates = template_types)

Robert Bradshaw's avatar
Robert Bradshaw committed
1205 1206
    def analyse_declarations(self, env):
        scope = None
1207
        if self.attributes is not None:
1208
            scope = CppClassScope(self.name, env, templates = self.templates)
1209
        base_class_types = [b.analyse(scope or env) for b in self.base_classes]
1210 1211 1212 1213
        if self.templates is None:
            template_types = None
        else:
            template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
1214
        self.entry = env.declare_cpp_class(
1215
            self.name, scope, self.pos,
1216
            self.cname, base_class_types, visibility = self.visibility, templates = template_types)
1217 1218
        if self.entry is None:
            return
Danilo Freitas's avatar
Danilo Freitas committed
1219
        self.entry.is_cpp_class = 1
Stefan Behnel's avatar
Stefan Behnel committed
1220 1221
        if scope is not None:
            scope.type = self.entry.type
1222
        defined_funcs = []
Robert Bradshaw's avatar
Robert Bradshaw committed
1223 1224 1225 1226
        if self.attributes is not None:
            if self.in_pxd and not env.in_cinclude:
                self.entry.defined_in_pxd = 1
            for attr in self.attributes:
Robert Bradshaw's avatar
Robert Bradshaw committed
1227
                attr.analyse_declarations(scope)
1228 1229
                if isinstance(attr, CFuncDefNode):
                    defined_funcs.append(attr)
1230 1231
                    if self.templates is not None:
                        attr.template_declaration = "template <typename %s>" % ", typename ".join(self.templates)
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
        self.body = StatListNode(self.pos, stats=defined_funcs)
        self.scope = scope

    def analyse_expressions(self, env):
        self.body.analyse_expressions(self.entry.type.scope)

    def generate_function_definitions(self, env, code):
        self.body.generate_function_definitions(self.entry.type.scope, code)

    def generate_execution_code(self, code):
        self.body.generate_execution_code(code)

    def annotate(self, code):
        self.body.annotate(code)

Robert Bradshaw's avatar
Robert Bradshaw committed
1247

William Stein's avatar
William Stein committed
1248 1249 1250 1251 1252
class CEnumDefNode(StatNode):
    #  name           string or None
    #  cname          string or None
    #  items          [CEnumDefItemNode]
    #  typedef_flag   boolean
Stefan Behnel's avatar
Stefan Behnel committed
1253
    #  visibility     "public" or "private"
1254
    #  api            boolean
Stefan Behnel's avatar
Stefan Behnel committed
1255
    #  in_pxd         boolean
William Stein's avatar
William Stein committed
1256
    #  entry          Entry
Robert Bradshaw's avatar
Robert Bradshaw committed
1257

1258
    child_attrs = ["items"]
1259

1260 1261 1262 1263 1264
    def declare(self, env):
         self.entry = env.declare_enum(self.name, self.pos,
             cname = self.cname, typedef_flag = self.typedef_flag,
             visibility = self.visibility, api = self.api)

William Stein's avatar
William Stein committed
1265
    def analyse_declarations(self, env):
Stefan Behnel's avatar
Stefan Behnel committed
1266 1267 1268 1269 1270
        if self.items is not None:
            if self.in_pxd and not env.in_cinclude:
                self.entry.defined_in_pxd = 1
            for item in self.items:
                item.analyse_declarations(env, self.entry)
William Stein's avatar
William Stein committed
1271

1272 1273 1274
    def analyse_expressions(self, env):
        pass

William Stein's avatar
William Stein committed
1275
    def generate_execution_code(self, code):
1276
        if self.visibility == 'public' or self.api:
1277
            temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
Robert Bradshaw's avatar
Robert Bradshaw committed
1278 1279
            for item in self.entry.enum_values:
                code.putln("%s = PyInt_FromLong(%s); %s" % (
1280
                        temp,
Robert Bradshaw's avatar
Robert Bradshaw committed
1281
                        item.cname,
1282
                        code.error_goto_if_null(temp, item.pos)))
Stefan Behnel's avatar
merge  
Stefan Behnel committed
1283
                code.put_gotref(temp)
1284
                code.putln('if (__Pyx_SetAttrString(%s, "%s", %s) < 0) %s' % (
1285 1286
                        Naming.module_cname,
                        item.name,
1287
                        temp,
Robert Bradshaw's avatar
Robert Bradshaw committed
1288
                        code.error_goto(item.pos)))
Stefan Behnel's avatar
merge  
Stefan Behnel committed
1289
                code.put_decref_clear(temp, PyrexTypes.py_object_type)
1290
            code.funcstate.release_temp(temp)
William Stein's avatar
William Stein committed
1291 1292 1293 1294 1295 1296


class CEnumDefItemNode(StatNode):
    #  name     string
    #  cname    string or None
    #  value    ExprNode or None
1297

1298 1299
    child_attrs = ["value"]

William Stein's avatar
William Stein committed
1300 1301 1302
    def analyse_declarations(self, env, enum_entry):
        if self.value:
            self.value.analyse_const_expression(env)
1303 1304 1305
            if not self.value.type.is_int:
                self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
                self.value.analyse_const_expression(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
1306
        entry = env.declare_const(self.name, enum_entry.type,
1307
            self.value, self.pos, cname = self.cname,
1308
            visibility = enum_entry.visibility, api = enum_entry.api)
William Stein's avatar
William Stein committed
1309 1310 1311 1312
        enum_entry.enum_values.append(entry)


class CTypeDefNode(StatNode):
Stefan Behnel's avatar
Stefan Behnel committed
1313 1314 1315
    #  base_type    CBaseTypeNode
    #  declarator   CDeclaratorNode
    #  visibility   "public" or "private"
1316
    #  api          boolean
Stefan Behnel's avatar
Stefan Behnel committed
1317
    #  in_pxd       boolean
1318 1319

    child_attrs = ["base_type", "declarator"]
1320

William Stein's avatar
William Stein committed
1321 1322 1323 1324 1325
    def analyse_declarations(self, env):
        base = self.base_type.analyse(env)
        name_declarator, type = self.declarator.analyse(base, env)
        name = name_declarator.name
        cname = name_declarator.cname
1326

Stefan Behnel's avatar
Stefan Behnel committed
1327
        entry = env.declare_typedef(name, type, self.pos,
1328
            cname = cname, visibility = self.visibility, api = self.api)
1329

Mark Florisson's avatar
Mark Florisson committed
1330
        if type.is_fused:
1331 1332
            entry.in_cinclude = True

Mark Florisson's avatar
Mark Florisson committed
1333 1334
        if self.in_pxd and not env.in_cinclude:
            entry.defined_in_pxd = 1
1335

William Stein's avatar
William Stein committed
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
    def analyse_expressions(self, env):
        pass
    def generate_execution_code(self, code):
        pass


class FuncDefNode(StatNode, BlockNode):
    #  Base class for function definition nodes.
    #
    #  return_type     PyrexType
    #  #filename        string        C name of filename string const
    #  entry           Symtab.Entry
1348
    #  needs_closure   boolean        Whether or not this function has inner functions/classes/yield
Vitja Makarov's avatar
Vitja Makarov committed
1349
    #  needs_outer_scope boolean      Whether or not this function requires outer scope
1350
    #  pymethdef_required boolean     Force Python method struct generation
1351 1352
    #  directive_locals { string : ExprNode } locals defined by cython.locals(...)
    #  directive_returns [ExprNode] type defined by cython.returns(...)
1353 1354
    # star_arg      PyArgDeclNode or None  * argument
    # starstar_arg  PyArgDeclNode or None  ** argument
1355

1356 1357 1358 1359 1360
    #  has_fused_arguments  boolean
    #       Whether this cdef function has fused parameters. This is needed
    #       by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes
    #       with fused argument types with a FusedCFuncDefNode

1361
    py_func = None
1362
    needs_closure = False
Vitja Makarov's avatar
Vitja Makarov committed
1363
    needs_outer_scope = False
1364
    pymethdef_required = False
1365
    is_generator = False
1366
    is_generator_body = False
Robert Bradshaw's avatar
Robert Bradshaw committed
1367
    modifiers = []
1368
    has_fused_arguments = False
1369 1370
    star_arg = None
    starstar_arg = None
1371
    is_cyfunction = False
1372

1373 1374
    def analyse_default_values(self, env):
        genv = env.global_scope()
1375
        default_seen = 0
1376 1377
        for arg in self.args:
            if arg.default:
1378
                default_seen = 1
1379
                if arg.is_generic:
1380 1381
                    arg.default.analyse_types(env)
                    arg.default = arg.default.coerce_to(arg.type, genv)
1382 1383 1384 1385
                else:
                    error(arg.pos,
                        "This argument cannot have a default value")
                    arg.default = None
1386 1387 1388 1389
            elif arg.kw_only:
                default_seen = 1
            elif default_seen:
                error(arg.pos, "Non-default argument following default argument")
1390

1391 1392 1393 1394 1395 1396 1397 1398
    def align_argument_type(self, env, arg):
        directive_locals = self.directive_locals
        type = arg.type
        if arg.name in directive_locals:
            type_node = directive_locals[arg.name]
            other_type = type_node.analyse_as_type(env)
            if other_type is None:
                error(type_node.pos, "Not a type")
Robert Bradshaw's avatar
Robert Bradshaw committed
1399
            elif (type is not PyrexTypes.py_object_type
1400 1401 1402 1403 1404 1405 1406
                    and not type.same_as(other_type)):
                error(arg.base_type.pos, "Signature does not agree with previous declaration")
                error(type_node.pos, "Previous declaration here")
            else:
                arg.type = other_type
        return arg

1407 1408
    def need_gil_acquisition(self, lenv):
        return 0
1409

1410 1411
    def create_local_scope(self, env):
        genv = env
1412
        while genv.is_py_class_scope or genv.is_c_class_scope:
1413
            genv = genv.outer_scope
1414
        if self.needs_closure:
1415 1416
            lenv = ClosureScope(name=self.entry.name,
                                outer_scope = genv,
1417
                                parent_scope = env,
1418
                                scope_name=self.entry.cname)
1419
        else:
1420 1421 1422
            lenv = LocalScope(name=self.entry.name,
                              outer_scope=genv,
                              parent_scope=env)
William Stein's avatar
William Stein committed
1423
        lenv.return_type = self.return_type
1424 1425 1426
        type = self.entry.type
        if type.is_cfunction:
            lenv.nogil = type.nogil and not type.with_gil
1427
        self.local_scope = lenv
1428
        lenv.directives = env.directives
1429
        return lenv
1430

1431 1432 1433
    def generate_function_body(self, env, code):
        self.body.generate_execution_code(code)

1434
    def generate_function_definitions(self, env, code):
1435 1436 1437
        import Buffer
        if self.return_type.is_memoryviewslice:
            import MemoryView
1438 1439

        lenv = self.local_scope
Vitja Makarov's avatar
Vitja Makarov committed
1440
        if lenv.is_closure_scope and not lenv.is_passthrough:
1441 1442 1443 1444 1445
            outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
                                            Naming.outer_scope_cname)
        else:
            outer_scope_cname = Naming.outer_scope_cname
        lenv.mangle_closure_cnames(outer_scope_cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
1446 1447
        # Generate closure function definitions
        self.body.generate_function_definitions(lenv, code)
Stefan Behnel's avatar
Stefan Behnel committed
1448
        # generate lambda function definitions
1449
        self.generate_lambda_definitions(lenv, code)
1450

1451 1452
        is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
                             self.entry.scope.is_c_class_scope)
1453 1454 1455
        is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and
                                 self.entry.scope.is_c_class_scope)
        is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot
1456
        if is_buffer_slot:
1457 1458
            if 'cython_unused' not in self.modifiers:
                self.modifiers = self.modifiers + ['cython_unused']
1459

1460
        preprocessor_guard = self.get_preprocessor_guard()
1461

1462
        profile = code.globalstate.directives['profile']
1463 1464 1465
        if profile and lenv.nogil:
            warning(self.pos, "Cannot profile nogil function.", 1)
            profile = False
Robert Bradshaw's avatar
Robert Bradshaw committed
1466
        if profile:
1467
            code.globalstate.use_utility_code(profile_utility_code)
1468

1469
        # Generate C code for header and body of function
1470
        code.enter_cfunc_scope()
1471
        code.return_from_error_cleanup_label = code.new_label()
1472

William Stein's avatar
William Stein committed
1473
        # ----- Top-level constants used by this function
1474
        code.mark_pos(self.pos)
1475
        self.generate_cached_builtins_decls(lenv, code)
William Stein's avatar
William Stein committed
1476 1477
        # ----- Function header
        code.putln("")
1478 1479 1480 1481

        if preprocessor_guard:
            code.putln(preprocessor_guard)

1482 1483
        with_pymethdef = (self.needs_assignment_synthesis(env, code) or
                          self.pymethdef_required)
1484
        if self.py_func:
1485
            self.py_func.generate_function_header(code,
Stefan Behnel's avatar
Stefan Behnel committed
1486
                with_pymethdef = with_pymethdef,
1487
                proto_only=True)
William Stein's avatar
William Stein committed
1488
        self.generate_function_header(code,
Stefan Behnel's avatar
Stefan Behnel committed
1489
            with_pymethdef = with_pymethdef)
William Stein's avatar
William Stein committed
1490
        # ----- Local variable declarations
1491 1492 1493 1494
        # Find function scope
        cenv = env
        while cenv.is_py_class_scope or cenv.is_c_class_scope:
            cenv = cenv.outer_scope
Vitja Makarov's avatar
Vitja Makarov committed
1495
        if self.needs_closure:
1496
            code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
Robert Bradshaw's avatar
Robert Bradshaw committed
1497
            code.putln(";")
Vitja Makarov's avatar
Vitja Makarov committed
1498 1499 1500 1501
        elif self.needs_outer_scope:
            if lenv.is_passthrough:
                code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
                code.putln(";")
1502
            code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
1503
            code.putln(";")
William Stein's avatar
William Stein committed
1504
        self.generate_argument_declarations(lenv, code)
1505

1506
        for entry in lenv.var_entries:
1507
            if not (entry.in_closure or entry.is_arg):
1508
                code.put_var_declaration(entry)
1509

1510
        # Initialize the return variable __pyx_r
William Stein's avatar
William Stein committed
1511 1512
        init = ""
        if not self.return_type.is_void:
1513 1514
            if self.return_type.is_pyobject:
                init = " = NULL"
1515
            elif self.return_type.is_memoryviewslice:
1516
                init = ' = ' + MemoryView.memslice_entry_init
1517

William Stein's avatar
William Stein committed
1518
            code.putln(
1519
                "%s%s;" %
1520 1521
                    (self.return_type.declaration_code(Naming.retval_cname),
                     init))
1522

1523
        tempvardecl_code = code.insertion_point()
William Stein's avatar
William Stein committed
1524
        self.generate_keyword_list(code)
1525

1526 1527
        if profile:
            code.put_trace_declarations()
1528

William Stein's avatar
William Stein committed
1529 1530
        # ----- Extern library function declarations
        lenv.generate_library_function_declarations(code)
1531

1532
        # ----- GIL acquisition
1533
        acquire_gil = self.acquire_gil
1534

Mark Florisson's avatar
Mark Florisson committed
1535 1536
        # See if we need to acquire the GIL for variable declarations, or for
        # refnanny only
1537

Mark Florisson's avatar
Mark Florisson committed
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
        # Profiling or closures are not currently possible for cdef nogil
        # functions, but check them anyway
        have_object_args = (self.needs_closure or self.needs_outer_scope or
                            profile)
        for arg in lenv.arg_entries:
            if arg.type.is_pyobject:
                have_object_args = True
                break

        acquire_gil_for_var_decls_only = (
                lenv.nogil and lenv.has_with_gil_block and
                (have_object_args or lenv.buffer_entries))

        acquire_gil_for_refnanny_only = (
                lenv.nogil and lenv.has_with_gil_block and not
                acquire_gil_for_var_decls_only)

        use_refnanny = not lenv.nogil or lenv.has_with_gil_block
1556 1557 1558

        if acquire_gil or acquire_gil_for_var_decls_only:
            code.put_ensure_gil()
1559 1560
        elif lenv.nogil and lenv.has_with_gil_block:
            code.declare_gilstate()
1561

1562
        # ----- set up refnanny
1563
        if use_refnanny:
1564
            tempvardecl_code.put_declare_refcount_context()
1565 1566
            code.put_setup_refcount_context(
                self.entry.name, acquire_gil=acquire_gil_for_refnanny_only)
Mark Florisson's avatar
Mark Florisson committed
1567

1568
        # ----- Automatic lead-ins for certain special functions
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1569 1570
        if is_getbuffer_slot:
            self.getbuffer_init(code)
1571
        # ----- Create closure scope object
Robert Bradshaw's avatar
Robert Bradshaw committed
1572
        if self.needs_closure:
1573
            code.putln("%s = (%s)%s->tp_new(%s, %s, NULL);" % (
1574 1575
                Naming.cur_scope_cname,
                lenv.scope_class.type.declaration_code(''),
1576
                lenv.scope_class.type.typeptr_cname,
1577
                lenv.scope_class.type.typeptr_cname,
1578 1579 1580 1581
                Naming.empty_tuple))
            code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname)
            if is_getbuffer_slot:
                self.getbuffer_error_cleanup(code)
1582 1583

            if use_refnanny:
1584
                code.put_finish_refcount_context()
Mark Florisson's avatar
Mark Florisson committed
1585
                if acquire_gil or acquire_gil_for_var_decls_only:
1586 1587
                    code.put_release_ensured_gil()

1588 1589 1590
            # FIXME: what if the error return value is a Python value?
            code.putln("return %s;" % self.error_value())
            code.putln("}")
Robert Bradshaw's avatar
Robert Bradshaw committed
1591
            code.put_gotref(Naming.cur_scope_cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
1592
            # Note that it is unsafe to decref the scope at this point.
Vitja Makarov's avatar
Vitja Makarov committed
1593
        if self.needs_outer_scope:
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
            if self.is_cyfunction:
                code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % (
                    outer_scope_cname,
                    cenv.scope_class.type.declaration_code(''),
                    Naming.self_cname))
            else:
                code.putln("%s = (%s) %s;" % (
                    outer_scope_cname,
                    cenv.scope_class.type.declaration_code(''),
                    Naming.self_cname))
Vitja Makarov's avatar
Vitja Makarov committed
1604 1605 1606
            if lenv.is_passthrough:
                code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname));
            elif self.needs_closure:
1607
                # inner closures own a reference to their outer parent
1608
                code.put_incref(outer_scope_cname, cenv.scope_class.type)
1609
                code.put_giveref(outer_scope_cname)
1610 1611 1612 1613 1614
        # ----- Trace function call
        if profile:
            # this looks a bit late, but if we don't get here due to a
            # fatal error before hand, it's not really worth tracing
            code.put_trace_call(self.entry.name, self.pos)
William Stein's avatar
William Stein committed
1615
        # ----- Fetch arguments
1616
        self.generate_argument_parsing_code(env, code)
1617
        # If an argument is assigned to in the body, we must
Robert Bradshaw's avatar
Robert Bradshaw committed
1618
        # incref it to properly keep track of refcounts.
1619
        is_cdef = isinstance(self, CFuncDefNode)
Robert Bradshaw's avatar
Robert Bradshaw committed
1620
        for entry in lenv.arg_entries:
1621
            if entry.type.is_pyobject:
1622 1623
                if ((acquire_gil or len(entry.cf_assignments) > 1) and
                    not entry.in_closure):
1624
                    code.put_var_incref(entry)
1625

1626
            # Note: defaults are always incref-ed. For def functions, we
1627 1628 1629
            #       we aquire arguments from object converstion, so we have
            #       new references. If we are a cdef function, we need to
            #       incref our arguments
Mark Florisson's avatar
Mark Florisson committed
1630 1631
            elif (is_cdef and entry.type.is_memoryviewslice and
                  len(entry.cf_assignments) > 1):
1632 1633
                code.put_incref_memoryviewslice(entry.cname,
                                                have_gil=not lenv.nogil)
1634 1635 1636
        for entry in lenv.var_entries:
            if entry.is_arg and len(entry.cf_assignments) > 1:
                code.put_var_incref(entry)
1637

1638 1639
        # ----- Initialise local buffer auxiliary variables
        for entry in lenv.var_entries + lenv.arg_entries:
1640 1641
            if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used:
                Buffer.put_init_vars(entry, code)
1642

1643
        # ----- Check and convert arguments
William Stein's avatar
William Stein committed
1644
        self.generate_argument_type_tests(code)
1645 1646 1647
        # ----- Acquire buffer arguments
        for entry in lenv.arg_entries:
            if entry.type.is_buffer:
1648 1649
                Buffer.put_acquire_arg_buffer(entry, code, self.pos)

1650 1651 1652
        if acquire_gil_for_var_decls_only:
            code.put_release_ensured_gil()

1653 1654 1655
        # -------------------------
        # ----- Function body -----
        # -------------------------
1656
        self.generate_function_body(env, code)
1657

William Stein's avatar
William Stein committed
1658 1659 1660 1661
        # ----- Default return value
        code.putln("")
        if self.return_type.is_pyobject:
            #if self.return_type.is_extension_type:
1662
            #    lhs = "(PyObject *)%s" % Naming.retval_cname
William Stein's avatar
William Stein committed
1663 1664 1665 1666 1667 1668 1669 1670
            #else:
            lhs = Naming.retval_cname
            code.put_init_to_py_none(lhs, self.return_type)
        else:
            val = self.return_type.default_value
            if val:
                code.putln("%s = %s;" % (Naming.retval_cname, val))
        # ----- Error cleanup
1671 1672 1673
        if code.error_label in code.labels_used:
            code.put_goto(code.return_label)
            code.put_label(code.error_label)
1674
            for cname, type in code.funcstate.all_managed_temps():
1675
                code.put_xdecref(cname, type, have_gil=not lenv.nogil)
1676 1677 1678 1679

            # Clean up buffers -- this calls a Python function
            # so need to save and restore error state
            buffers_present = len(lenv.buffer_entries) > 0
1680 1681
            memslice_entries = [e for e in lenv.entries.itervalues()
                                      if e.type.is_memoryviewslice]
1682
            if buffers_present:
1683
                code.globalstate.use_utility_code(restore_exception_utility_code)
1684
                code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
1685
                code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
1686
                for entry in lenv.buffer_entries:
1687
                    Buffer.put_release_buffer_code(code, entry)
1688
                    #code.putln("%s = 0;" % entry.cname)
1689
                code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
1690

1691 1692 1693 1694 1695 1696
            if self.return_type.is_memoryviewslice:
                MemoryView.put_init_entry(Naming.retval_cname, code)
                err_val = Naming.retval_cname
            else:
                err_val = self.error_value()

1697 1698
            exc_check = self.caller_will_check_exceptions()
            if err_val is not None or exc_check:
1699
                # TODO: Fix exception tracing (though currently unused by cProfile).
Robert Bradshaw's avatar
Robert Bradshaw committed
1700 1701
                # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
                # code.put_trace_exception()
1702

Mark Florisson's avatar
Mark Florisson committed
1703
                if lenv.nogil and not lenv.has_with_gil_block:
1704 1705 1706
                    code.putln("{")
                    code.put_ensure_gil()

1707
                code.put_add_traceback(self.entry.qualified_name)
1708

Mark Florisson's avatar
Mark Florisson committed
1709
                if lenv.nogil and not lenv.has_with_gil_block:
1710 1711
                    code.put_release_ensured_gil()
                    code.putln("}")
1712
            else:
1713 1714
                warning(self.entry.pos, "Unraisable exception in function '%s'." \
                            % self.entry.qualified_name, 0)
1715 1716 1717 1718 1719 1720
                format_tuple = (
                    self.entry.qualified_name,
                    Naming.clineno_cname,
                    Naming.lineno_cname,
                    Naming.filename_cname,
                    )
1721
                code.putln(
1722
                    '__Pyx_WriteUnraisable("%s", %s, %s, %s);' % format_tuple)
1723
                env.use_utility_code(unraisable_exception_utility_code)
1724
                env.use_utility_code(restore_exception_utility_code)
1725 1726 1727 1728
            default_retval = self.return_type.default_value
            if err_val is None and default_retval:
                err_val = default_retval
            if err_val is not None:
1729
                code.putln("%s = %s;" % (Naming.retval_cname, err_val))
1730 1731 1732 1733 1734 1735 1736 1737

            if is_getbuffer_slot:
                self.getbuffer_error_cleanup(code)

            # If we are using the non-error cleanup section we should
            # jump past it if we have an error. The if-test below determine
            # whether this section is used.
            if buffers_present or is_getbuffer_slot:
1738 1739 1740
                code.put_goto(code.return_from_error_cleanup_label)

        # ----- Non-error return cleanup
William Stein's avatar
William Stein committed
1741
        code.put_label(code.return_label)
1742
        for entry in lenv.buffer_entries:
1743
            if entry.used:
1744
                Buffer.put_release_buffer_code(code, entry)
1745 1746
        if is_getbuffer_slot:
            self.getbuffer_normal_cleanup(code)
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766

        if self.return_type.is_memoryviewslice:
            # See if our return value is uninitialized on non-error return
            # import MemoryView
            # MemoryView.err_if_nogil_initialized_check(self.pos, env)
            cond = code.unlikely(self.return_type.error_condition(
                                                    Naming.retval_cname))
            code.putln(
                'if (%s) {' % cond)
            if env.nogil:
                code.put_ensure_gil()
            code.putln(
                    'PyErr_SetString('
                        'PyExc_TypeError,'
                        '"Memoryview return value is not initialized");')
            if env.nogil:
                code.put_release_ensured_gil()
            code.putln(
                '}')

1767 1768
        # ----- Return cleanup for both error and no-error return
        code.put_label(code.return_from_error_cleanup_label)
1769

1770
        for entry in lenv.var_entries:
1771 1772
            if not entry.used or entry.in_closure:
                continue
1773

1774
            if entry.type.is_memoryviewslice:
1775 1776
                code.put_xdecref_memoryviewslice(entry.cname,
                                                 have_gil=not lenv.nogil)
1777
            elif entry.type.is_pyobject:
1778 1779
                if not entry.is_arg or len(entry.cf_assignments) > 1:
                    code.put_var_decref(entry)
1780

Robert Bradshaw's avatar
Robert Bradshaw committed
1781
        # Decref any increfed args
1782
        for entry in lenv.arg_entries:
1783
            if entry.type.is_pyobject:
1784 1785
                if ((acquire_gil or len(entry.cf_assignments) > 1) and
                    not entry.in_closure):
1786
                    code.put_var_decref(entry)
1787 1788 1789 1790
            elif (entry.type.is_memoryviewslice and
                  (not is_cdef or len(entry.cf_assignments) > 1)):
                # decref slices of def functions and acquired slices from cdef
                # functions, but not borrowed slices from cdef functions.
1791 1792
                code.put_xdecref_memoryviewslice(entry.cname,
                                                 have_gil=not lenv.nogil)
Robert Bradshaw's avatar
Robert Bradshaw committed
1793 1794
        if self.needs_closure:
            code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
1795

1796
        # ----- Return
1797
        # This code is duplicated in ModuleNode.generate_module_init_func
1798 1799 1800 1801 1802 1803 1804
        if not lenv.nogil:
            default_retval = self.return_type.default_value
            err_val = self.error_value()
            if err_val is None and default_retval:
                err_val = default_retval
            if self.return_type.is_pyobject:
                code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
1805

1806 1807
        if self.entry.is_special and self.entry.name == "__hash__":
            # Returning -1 for __hash__ is supposed to signal an error
1808
            # We do as Python instances and coerce -1 into -2.
1809 1810
            code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (
                    Naming.retval_cname, Naming.retval_cname))
1811

Robert Bradshaw's avatar
Robert Bradshaw committed
1812 1813 1814 1815 1816
        if profile:
            if self.return_type.is_pyobject:
                code.put_trace_return(Naming.retval_cname)
            else:
                code.put_trace_return("Py_None")
1817

1818
        if not lenv.nogil:
1819
            # GIL holding funcion
1820
            code.put_finish_refcount_context()
1821

1822 1823
        if acquire_gil or (lenv.nogil and lenv.has_with_gil_block):
            # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
1824
            code.put_release_ensured_gil()
1825

William Stein's avatar
William Stein committed
1826
        if not self.return_type.is_void:
1827
            code.putln("return %s;" % Naming.retval_cname)
1828

William Stein's avatar
William Stein committed
1829
        code.putln("}")
1830 1831 1832 1833

        if preprocessor_guard:
            code.putln("#endif /*!(%s)*/" % preprocessor_guard)

1834
        # ----- Go back and insert temp variable declarations
1835
        tempvardecl_code.put_temp_declarations(code.funcstate)
1836
        if code.funcstate.should_declare_error_indicator:
1837
            # Initialize these variables to silence compiler warnings
Mark Florisson's avatar
Mark Florisson committed
1838 1839 1840
            tempvardecl_code.putln("int %s = 0;" % Naming.lineno_cname)
            tempvardecl_code.putln("const char *%s = NULL;" %
                                                    Naming.filename_cname)
1841
            if code.c_line_in_traceback:
Mark Florisson's avatar
Mark Florisson committed
1842
                tempvardecl_code.putln("int %s = 0;" % Naming.clineno_cname)
1843

1844
        # ----- Python version
1845
        code.exit_cfunc_scope()
1846
        if self.py_func:
1847
            self.py_func.generate_function_definitions(env, code)
1848
        self.generate_wrapper_functions(code)
William Stein's avatar
William Stein committed
1849 1850 1851 1852

    def declare_argument(self, env, arg):
        if arg.type.is_void:
            error(arg.pos, "Invalid use of 'void'")
1853
        elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice):
William Stein's avatar
William Stein committed
1854 1855 1856
            error(arg.pos,
                "Argument type '%s' is incomplete" % arg.type)
        return env.declare_arg(arg.name, arg.type, arg.pos)
1857

1858 1859 1860
    def generate_arg_type_test(self, arg, code):
        # Generate type test for one argument.
        if arg.type.typeobj_is_available():
1861 1862
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("ArgTypeTest", "FunctionArguments.c"))
1863 1864 1865 1866
            typeptr_cname = arg.type.typeptr_cname
            arg_code = "((PyObject *)%s)" % arg.entry.cname
            code.putln(
                'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
1867
                    arg_code,
1868 1869 1870 1871 1872 1873 1874 1875
                    typeptr_cname,
                    arg.accept_none,
                    arg.name,
                    arg.type.is_builtin_type,
                    code.error_goto(arg.pos)))
        else:
            error(arg.pos, "Cannot test type of extern C class "
                "without type object name specification")
1876 1877 1878

    def generate_arg_none_check(self, arg, code):
        # Generate None check for one argument.
1879 1880 1881 1882 1883 1884
        if arg.type.is_memoryviewslice:
            cname = "%s.memview" % arg.entry.cname
        else:
            cname = arg.entry.cname

        code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % cname)
1885 1886 1887 1888
        code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
            arg.name,
            code.error_goto(arg.pos)))
        code.putln('}')
1889

1890
    def generate_wrapper_functions(self, code):
William Stein's avatar
William Stein committed
1891 1892 1893
        pass

    def generate_execution_code(self, code):
1894 1895
        # Evaluate and store argument default values
        for arg in self.args:
1896 1897
            if not arg.is_dynamic:
                arg.generate_assignment_code(code)
William Stein's avatar
William Stein committed
1898

1899
    #
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1900
    # Special code for the __getbuffer__ function
1901 1902 1903 1904 1905
    #
    def getbuffer_init(self, code):
        info = self.local_scope.arg_entries[1].cname
        # Python 3.0 betas have a bug in memoryview which makes it call
        # getbuffer with a NULL parameter. For now we work around this;
1906 1907
        # the following block should be removed when this bug is fixed.
        code.putln("if (%s != NULL) {" % info)
1908
        code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
1909
        code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
1910
        code.putln("}")
1911 1912 1913

    def getbuffer_error_cleanup(self, code):
        info = self.local_scope.arg_entries[1].cname
1914 1915
        code.putln("if (%s != NULL && %s->obj != NULL) {"
                   % (info, info))
1916
        code.put_gotref("%s->obj" % info)
1917 1918 1919
        code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;"
                   % (info, info))
        code.putln("}")
1920 1921 1922

    def getbuffer_normal_cleanup(self, code):
        info = self.local_scope.arg_entries[1].cname
1923
        code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info))
1924 1925 1926
        code.put_gotref("Py_None")
        code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
        code.putln("}")
William Stein's avatar
William Stein committed
1927

1928
    def get_preprocessor_guard(self):
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
        if not self.entry.is_special:
            return None
        name = self.entry.name
        slot = TypeSlots.method_name_to_slot.get(name)
        if not slot:
            return None
        if name == '__long__' and not self.entry.scope.lookup_here('__int__'):
            return None
        if name in ("__getbuffer__", "__releasebuffer__") and self.entry.scope.is_c_class_scope:
            return None
        return slot.preprocessor_guard_code()
1940 1941


William Stein's avatar
William Stein committed
1942 1943 1944
class CFuncDefNode(FuncDefNode):
    #  C function definition.
    #
Robert Bradshaw's avatar
Robert Bradshaw committed
1945
    #  modifiers     ['inline']
William Stein's avatar
William Stein committed
1946 1947 1948
    #  visibility    'private' or 'public' or 'extern'
    #  base_type     CBaseTypeNode
    #  declarator    CDeclaratorNode
1949 1950 1951
    #  cfunc_declarator  the CFuncDeclarator of this function
    #                    (this is also available through declarator or a
    #                     base thereof)
William Stein's avatar
William Stein committed
1952
    #  body          StatListNode
1953
    #  api           boolean
1954
    #  decorators    [DecoratorNode]        list of decorators
William Stein's avatar
William Stein committed
1955
    #
1956
    #  with_gil      boolean    Acquire GIL around body
William Stein's avatar
William Stein committed
1957
    #  type          CFuncType
1958
    #  py_func       wrapper for calling from Python
1959
    #  overridable   whether or not this is a cpdef function
1960
    #  inline_in_pxd whether this is an inline function in a pxd file
1961
    #  template_declaration  String or None   Used for c++ class methods
1962

1963
    child_attrs = ["base_type", "declarator", "body", "py_func"]
1964 1965

    inline_in_pxd = False
1966
    decorators = None
1967
    directive_locals = None
1968
    directive_returns = None
1969
    override = None
1970
    template_declaration = None
1971

William Stein's avatar
William Stein committed
1972 1973
    def unqualified_name(self):
        return self.entry.name
1974

William Stein's avatar
William Stein committed
1975
    def analyse_declarations(self, env):
1976 1977
        if self.directive_locals is None:
            self.directive_locals = {}
1978
        self.directive_locals.update(env.directives['locals'])
1979 1980 1981 1982 1983 1984 1985
        if self.directive_returns is not None:
            base_type = self.directive_returns.analyse_as_type(env)
            if base_type is None:
                error(self.directive_returns.pos, "Not a type")
                base_type = PyrexTypes.error_type
        else:
            base_type = self.base_type.analyse(env)
1986
        # The 2 here is because we need both function and argument names.
1987 1988 1989 1990 1991 1992
        if isinstance(self.declarator, CFuncDeclaratorNode):
            name_declarator, type = self.declarator.analyse(base_type, env,
                                                            nonempty = 2 * (self.body is not None),
                                                            directive_locals = self.directive_locals)
        else:
            name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
1993
        if not type.is_cfunction:
1994
            error(self.pos,
1995
                "Suite attached to non-function declaration")
William Stein's avatar
William Stein committed
1996 1997 1998 1999 2000
        # Remember the actual type according to the function header
        # written here, because the type in the symbol table entry
        # may be different if we're overriding a C method inherited
        # from the base type of an extension type.
        self.type = type
2001
        type.is_overridable = self.overridable
2002 2003 2004
        declarator = self.declarator
        while not hasattr(declarator, 'args'):
            declarator = declarator.base
2005 2006

        self.cfunc_declarator = declarator
2007
        self.args = declarator.args
2008

2009 2010 2011 2012 2013 2014
        opt_arg_count = self.cfunc_declarator.optional_arg_count
        if (self.visibility == 'public' or self.api) and opt_arg_count:
            error(self.cfunc_declarator.pos,
                  "Function with optional arguments may not be declared "
                  "public or api")

2015
        for formal_arg, type_arg in zip(self.args, type.args):
2016
            self.align_argument_type(env, type_arg)
2017
            formal_arg.type = type_arg.type
2018
            formal_arg.name = type_arg.name
2019
            formal_arg.cname = type_arg.cname
2020

2021 2022
            self._validate_type_visibility(type_arg.type, type_arg.pos, env)

2023 2024 2025
            if type_arg.type.is_fused:
                self.has_fused_arguments = True

2026 2027
            if type_arg.type.is_buffer and 'inline' in self.modifiers:
                warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)
2028

2029 2030 2031 2032 2033 2034 2035 2036
            if type_arg.type.is_buffer:
                if self.type.nogil:
                    error(formal_arg.pos,
                          "Buffer may not be acquired without the GIL. "
                          "Consider using memoryview slices instead.")
                elif 'inline' in self.modifiers:
                    warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1)

2037 2038
        self._validate_type_visibility(type.return_type, self.pos, env)

William Stein's avatar
William Stein committed
2039 2040
        name = name_declarator.name
        cname = name_declarator.cname
2041

William Stein's avatar
William Stein committed
2042
        self.entry = env.declare_cfunction(
2043
            name, type, self.pos,
2044 2045
            cname = cname, visibility = self.visibility, api = self.api,
            defining = self.body is not None, modifiers = self.modifiers)
2046
        self.entry.inline_func_in_pxd = self.inline_in_pxd
William Stein's avatar
William Stein committed
2047
        self.return_type = type.return_type
2048
        if self.return_type.is_array and self.visibility != 'extern':
2049 2050
            error(self.pos,
                "Function cannot return an array")
2051 2052
        if self.return_type.is_cpp_class:
            self.return_type.check_nullary_constructor(self.pos, "used as a return value")
2053

2054 2055 2056 2057
        if self.overridable and not env.is_module_scope:
            if len(self.args) < 1 or not self.args[0].type.is_pyobject:
                # An error will be produced in the cdef function
                self.overridable = False
2058

2059 2060 2061 2062
        self.declare_cpdef_wrapper(env)
        self.create_local_scope(env)

    def declare_cpdef_wrapper(self, env):
2063
        if self.overridable:
2064
            name = self.entry.name
2065
            py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
2066
            self.py_func = DefNode(pos = self.pos,
2067 2068
                                   name = self.entry.name,
                                   args = self.args,
2069 2070
                                   star_arg = None,
                                   starstar_arg = None,
2071
                                   doc = self.doc,
2072 2073
                                   body = py_func_body,
                                   is_wrapper = 1)
2074
            self.py_func.is_module_scope = env.is_module_scope
2075
            self.py_func.analyse_declarations(env)
2076
            self.entry.as_variable = self.py_func.entry
2077
            self.entry.used = self.entry.as_variable.used = True
2078 2079
            # Reset scope entry the above cfunction
            env.entries[name] = self.entry
2080 2081
            if (not self.entry.is_final_cmethod and
                (not env.is_module_scope or Options.lookup_module_cpdef)):
2082 2083
                self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
                self.body = StatListNode(self.pos, stats=[self.override, self.body])
2084

2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097
    def _validate_type_visibility(self, type, pos, env):
        """
        Ensure that types used in cdef functions are public or api, or
        defined in a C header.
        """
        public_or_api = (self.visibility == 'public' or self.api)
        entry = getattr(type, 'entry', None)
        if public_or_api and entry and env.is_module_scope:
            if not (entry.visibility in ('public', 'extern') or
                    entry.api or entry.in_cinclude):
                error(pos, "Function declared public or api may not have "
                           "private types")

2098
    def call_self_node(self, omit_optional_args=0, is_module_scope=0):
2099 2100 2101 2102 2103
        import ExprNodes
        args = self.type.args
        if omit_optional_args:
            args = args[:len(args) - self.type.optional_arg_count]
        arg_names = [arg.name for arg in args]
2104
        if is_module_scope:
2105
            cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
2106 2107
        else:
            self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
2108
            cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
2109 2110
        skip_dispatch = not is_module_scope or Options.lookup_module_cpdef
        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)
2111
        return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
2112

William Stein's avatar
William Stein committed
2113 2114 2115 2116 2117
    def declare_arguments(self, env):
        for arg in self.type.args:
            if not arg.name:
                error(arg.pos, "Missing argument name")
            self.declare_argument(env, arg)
2118

2119
    def need_gil_acquisition(self, lenv):
2120 2121
        return self.type.with_gil

2122
    def nogil_check(self, env):
2123
        type = self.type
2124
        with_gil = type.with_gil
2125 2126 2127 2128
        if type.nogil and not with_gil:
            if type.return_type.is_pyobject:
                error(self.pos,
                      "Function with Python return type cannot be declared nogil")
2129
            for entry in self.local_scope.var_entries:
2130
                if entry.type.is_pyobject and not entry.in_with_gil_block:
2131 2132
                    error(self.pos, "Function declared nogil has Python locals or temporaries")

2133
    def analyse_expressions(self, env):
2134
        self.local_scope.directives = env.directives
2135
        if self.py_func is not None:
2136
            # this will also analyse the default values
2137
            self.py_func.analyse_expressions(env)
2138 2139
        else:
            self.analyse_default_values(env)
2140
        self.acquire_gil = self.need_gil_acquisition(self.local_scope)
2141

Robert Bradshaw's avatar
Robert Bradshaw committed
2142 2143 2144
    def needs_assignment_synthesis(self, env, code=None):
        return False

2145
    def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
2146
        scope = self.local_scope
William Stein's avatar
William Stein committed
2147 2148
        arg_decls = []
        type = self.type
2149
        for arg in type.args[:len(type.args)-type.optional_arg_count]:
2150 2151 2152 2153 2154
            arg_decl = arg.declaration_code()
            entry = scope.lookup(arg.name)
            if not entry.cf_used:
                arg_decl = 'CYTHON_UNUSED %s' % arg_decl
            arg_decls.append(arg_decl)
2155
        if with_dispatch and self.overridable:
2156 2157 2158 2159 2160 2161
            dispatch_arg = PyrexTypes.c_int_type.declaration_code(
                Naming.skip_dispatch_cname)
            if self.override:
                arg_decls.append(dispatch_arg)
            else:
                arg_decls.append('CYTHON_UNUSED %s' % dispatch_arg)
2162 2163
        if type.optional_arg_count and with_opt_args:
            arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
William Stein's avatar
William Stein committed
2164 2165 2166 2167
        if type.has_varargs:
            arg_decls.append("...")
        if not arg_decls:
            arg_decls = ["void"]
2168 2169
        if cname is None:
            cname = self.entry.func_cname
2170
        entity = type.function_header_code(cname, ', '.join(arg_decls))
2171
        if self.entry.visibility == 'private' and '::' not in cname:
2172
            storage_class = "static "
William Stein's avatar
William Stein committed
2173
        else:
2174
            storage_class = ""
2175
        dll_linkage = None
2176
        modifiers = code.build_function_modifiers(self.entry.func_modifiers)
Robert Bradshaw's avatar
Robert Bradshaw committed
2177

2178 2179
        header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
        #print (storage_class, modifiers, header)
2180 2181
        if self.template_declaration:
            code.putln(self.template_declaration)
2182
        code.putln("%s%s%s {" % (storage_class, modifiers, header))
William Stein's avatar
William Stein committed
2183 2184

    def generate_argument_declarations(self, env, code):
2185
        scope = self.local_scope
2186
        for arg in self.args:
2187
            if arg.default:
2188
                entry = scope.lookup(arg.name)
2189
                if self.override or entry.cf_used:
2190 2191 2192
                    result = arg.calculate_default_value_code(code)
                    code.putln('%s = %s;' % (
                        arg.type.declaration_code(arg.cname), result))
2193

William Stein's avatar
William Stein committed
2194 2195
    def generate_keyword_list(self, code):
        pass
2196

2197
    def generate_argument_parsing_code(self, env, code):
2198
        i = 0
2199
        used = 0
2200
        if self.type.optional_arg_count:
2201
            scope = self.local_scope
2202
            code.putln('if (%s) {' % Naming.optional_args_cname)
2203
            for arg in self.args:
2204
                if arg.default:
2205
                    entry = scope.lookup(arg.name)
2206
                    if self.override or entry.cf_used:
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216
                        code.putln('if (%s->%sn > %s) {' %
                                   (Naming.optional_args_cname,
                                    Naming.pyrex_prefix, i))
                        declarator = arg.declarator
                        while not hasattr(declarator, 'name'):
                            declarator = declarator.base
                        code.putln('%s = %s->%s;' %
                                   (arg.cname, Naming.optional_args_cname,
                                    self.type.opt_arg_cname(declarator.name)))
                        used += 1
2217
                    i += 1
2218
            for _ in range(used):
2219
                code.putln('}')
2220
            code.putln('}')
2221

William Stein's avatar
William Stein committed
2222 2223
    def generate_argument_conversion_code(self, code):
        pass
2224

William Stein's avatar
William Stein committed
2225
    def generate_argument_type_tests(self, code):
2226 2227 2228 2229 2230
        # Generate type tests for args whose type in a parent
        # class is a supertype of the declared type.
        for arg in self.type.args:
            if arg.needs_type_test:
                self.generate_arg_type_test(arg, code)
2231 2232
            elif arg.type.is_pyobject and not arg.accept_none:
                self.generate_arg_none_check(arg, code)
2233

William Stein's avatar
William Stein committed
2234 2235 2236 2237
    def error_value(self):
        if self.return_type.is_pyobject:
            return "0"
        else:
2238 2239
            #return None
            return self.entry.type.exception_value
2240

William Stein's avatar
William Stein committed
2241
    def caller_will_check_exceptions(self):
2242
        return self.entry.type.exception_check
2243

2244 2245
    def generate_wrapper_functions(self, code):
        # If the C signature of a function has changed, we need to generate
2246
        # wrappers to put in the slots here.
2247 2248 2249 2250 2251 2252 2253
        k = 0
        entry = self.entry
        func_type = entry.type
        while entry.prev_entry is not None:
            k += 1
            entry = entry.prev_entry
            entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
2254
            code.putln()
2255
            self.generate_function_header(code,
2256
                                          0,
2257 2258
                                          with_dispatch = entry.type.is_overridable,
                                          with_opt_args = entry.type.optional_arg_count,
2259
                                          cname = entry.func_cname)
2260 2261 2262 2263
            if not self.return_type.is_void:
                code.put('return ')
            args = self.type.args
            arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
2264 2265 2266 2267 2268 2269 2270 2271
            if entry.type.is_overridable:
                arglist.append(Naming.skip_dispatch_cname)
            elif func_type.is_overridable:
                arglist.append('0')
            if entry.type.optional_arg_count:
                arglist.append(Naming.optional_args_cname)
            elif func_type.optional_arg_count:
                arglist.append('NULL')
2272 2273
            code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
            code.putln('}')
2274

William Stein's avatar
William Stein committed
2275 2276 2277 2278 2279

class PyArgDeclNode(Node):
    # Argument which must be a Python object (used
    # for * and ** arguments).
    #
2280 2281 2282
    # name        string
    # entry       Symtab.Entry
    # annotation  ExprNode or None   Py3 argument annotation
2283
    child_attrs = []
2284 2285
    is_self_arg = False
    is_type_arg = False
2286 2287 2288

    def generate_function_definitions(self, env, code):
        self.entry.generate_function_definitions(env, code)
2289 2290 2291 2292

class DecoratorNode(Node):
    # A decorator
    #
2293
    # decorator    NameNode or CallNode or AttributeNode
2294 2295
    child_attrs = ['decorator']

William Stein's avatar
William Stein committed
2296 2297 2298 2299 2300

class DefNode(FuncDefNode):
    # A Python function definition.
    #
    # name          string                 the Python name of the function
Stefan Behnel's avatar
Stefan Behnel committed
2301
    # lambda_name   string                 the internal name of a lambda 'function'
2302
    # decorators    [DecoratorNode]        list of decorators
William Stein's avatar
William Stein committed
2303
    # args          [CArgDeclNode]         formal arguments
2304
    # doc           EncodedString or None
William Stein's avatar
William Stein committed
2305
    # body          StatListNode
2306 2307
    # return_type_annotation
    #               ExprNode or None       the Py3 return type annotation
William Stein's avatar
William Stein committed
2308 2309 2310 2311
    #
    #  The following subnode is constructed internally
    #  when the def statement is inside a Python class definition.
    #
2312 2313 2314
    #  fused_py_func        DefNode     The original fused cpdef DefNode
    #                                   (in case this is a specialization)
    #  specialized_cpdefs   [DefNode]   list of specialized cpdef DefNodes
2315
    #  py_cfunc_node  PyCFunctionNode/InnerFunctionNode   The PyCFunction to create and assign
2316 2317
    #
    # decorator_indirection IndirectionNode Used to remove __Pyx_Method_ClassMethod for fused functions
2318

2319
    child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
2320

Stefan Behnel's avatar
Stefan Behnel committed
2321
    lambda_name = None
2322
    reqd_kw_flags_cname = "0"
2323
    is_wrapper = 0
2324
    no_assignment_synthesis = 0
2325
    decorators = None
2326
    return_type_annotation = None
2327
    entry = None
Robert Bradshaw's avatar
Robert Bradshaw committed
2328
    acquire_gil = 0
2329
    self_in_stararg = 0
2330
    py_cfunc_node = None
2331
    requires_classobj = False
2332
    defaults_struct = None # Dynamic kwrds structure name
2333
    doc = None
2334

2335 2336
    fused_py_func = False
    specialized_cpdefs = None
2337 2338 2339
    py_wrapper = None
    py_wrapper_required = True
    func_cname = None
2340

2341 2342
    defaults_getter = None

2343 2344
    def __init__(self, pos, **kwds):
        FuncDefNode.__init__(self, pos, **kwds)
2345
        k = rk = r = 0
2346 2347
        for arg in self.args:
            if arg.kw_only:
2348
                k += 1
2349
                if not arg.default:
2350 2351 2352 2353 2354 2355
                    rk += 1
            if not arg.default:
                r += 1
        self.num_kwonly_args = k
        self.num_required_kw_args = rk
        self.num_required_args = r
2356

2357
    def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None):
2358 2359 2360 2361
        if self.star_arg:
            error(self.star_arg.pos, "cdef function cannot have star argument")
        if self.starstar_arg:
            error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376
        if cfunc is None:
            cfunc_args = []
            for formal_arg in self.args:
                name_declarator, type = formal_arg.analyse(scope, nonempty=1)
                cfunc_args.append(PyrexTypes.CFuncTypeArg(name = name_declarator.name,
                                                          cname = None,
                                                          type = py_object_type,
                                                          pos = formal_arg.pos))
            cfunc_type = PyrexTypes.CFuncType(return_type = py_object_type,
                                              args = cfunc_args,
                                              has_varargs = False,
                                              exception_value = None,
                                              exception_check = False,
                                              nogil = False,
                                              with_gil = False,
Haoyu Bai's avatar
Haoyu Bai committed
2377
                                              is_overridable = overridable)
2378
            cfunc = CVarDefNode(self.pos, type=cfunc_type)
2379
        else:
2380 2381
            if scope is None:
                scope = cfunc.scope
2382 2383 2384
            cfunc_type = cfunc.type
            if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
                error(self.pos, "wrong number of arguments")
Stefan Behnel's avatar
Stefan Behnel committed
2385
                error(cfunc.pos, "previous declaration here")
2386 2387 2388
            for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)):
                name_declarator, type = formal_arg.analyse(scope, nonempty=1,
                                                           is_self_arg = (i == 0 and scope.is_c_class_scope))
Stefan Behnel's avatar
Stefan Behnel committed
2389
                if type is None or type is PyrexTypes.py_object_type:
2390 2391
                    formal_arg.type = type_arg.type
                    formal_arg.name_declarator = name_declarator
2392
        import ExprNodes
2393
        if cfunc_type.exception_value is None:
2394 2395
            exception_value = None
        else:
2396
            exception_value = ExprNodes.ConstNode(self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type)
2397
        declarator = CFuncDeclaratorNode(self.pos,
2398 2399 2400
                                         base = CNameDeclaratorNode(self.pos, name=self.name, cname=None),
                                         args = self.args,
                                         has_varargs = False,
2401
                                         exception_check = cfunc_type.exception_check,
2402
                                         exception_value = exception_value,
2403 2404
                                         with_gil = cfunc_type.with_gil,
                                         nogil = cfunc_type.nogil)
2405
        return CFuncDefNode(self.pos,
2406
                            modifiers = [],
2407
                            base_type = CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type),
2408 2409 2410
                            declarator = declarator,
                            body = self.body,
                            doc = self.doc,
2411 2412 2413 2414
                            overridable = cfunc_type.is_overridable,
                            type = cfunc_type,
                            with_gil = cfunc_type.with_gil,
                            nogil = cfunc_type.nogil,
2415
                            visibility = 'private',
2416
                            api = False,
2417 2418
                            directive_locals = getattr(cfunc, 'directive_locals', {}),
                            directive_returns = returns)
2419

2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430
    def is_cdef_func_compatible(self):
        """Determines if the function's signature is compatible with a
        cdef function.  This can be used before calling
        .as_cfunction() to see if that will be successful.
        """
        if self.needs_closure:
            return False
        if self.star_arg or self.starstar_arg:
            return False
        return True

William Stein's avatar
William Stein committed
2431
    def analyse_declarations(self, env):
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446
        self.is_classmethod = self.is_staticmethod = False
        if self.decorators:
            for decorator in self.decorators:
                func = decorator.decorator
                if func.is_name:
                    self.is_classmethod |= func.name == 'classmethod'
                    self.is_staticmethod |= func.name == 'staticmethod'

        if self.is_classmethod and env.lookup_here('classmethod'):
            # classmethod() was overridden - not much we can do here ...
            self.is_classmethod = False
        if self.is_staticmethod and env.lookup_here('staticmethod'):
            # staticmethod() was overridden - not much we can do here ...
            self.is_staticmethod = False

2447
        if self.name == '__new__' and env.is_py_class_scope:
Vitja Makarov's avatar
Vitja Makarov committed
2448 2449
            self.is_staticmethod = 1

2450
        self.analyse_argument_types(env)
2451 2452 2453 2454
        if self.name == '<lambda>':
            self.declare_lambda_function(env)
        else:
            self.declare_pyfunction(env)
2455

2456 2457 2458 2459
        self.analyse_signature(env)
        self.return_type = self.entry.signature.return_type()
        self.create_local_scope(env)

2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
        self.py_wrapper = DefNodeWrapper(
            self.pos,
            target=self,
            name=self.entry.name,
            args=self.args,
            star_arg=self.star_arg,
            starstar_arg=self.starstar_arg,
            return_type=self.return_type)
        self.py_wrapper.analyse_declarations(env)

2470
    def analyse_argument_types(self, env):
2471
        directive_locals = self.directive_locals = env.directives['locals']
2472
        allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
2473 2474 2475 2476

        f2s = env.fused_to_specific
        env.fused_to_specific = None

William Stein's avatar
William Stein committed
2477
        for arg in self.args:
2478 2479 2480 2481 2482 2483 2484
            if hasattr(arg, 'name'):
                name_declarator = None
            else:
                base_type = arg.base_type.analyse(env)
                name_declarator, type = \
                    arg.declarator.analyse(base_type, env)
                arg.name = name_declarator.name
2485
                arg.type = type
2486 2487 2488 2489

                if type.is_fused:
                    self.has_fused_arguments = True

2490
            self.align_argument_type(env, arg)
2491
            if name_declarator and name_declarator.cname:
William Stein's avatar
William Stein committed
2492 2493
                error(self.pos,
                    "Python function argument cannot have C name specification")
2494
            arg.type = arg.type.as_argument_type()
William Stein's avatar
William Stein committed
2495 2496 2497 2498
            arg.hdr_type = None
            arg.needs_conversion = 0
            arg.needs_type_test = 0
            arg.is_generic = 1
2499
            if arg.type.is_pyobject or arg.type.is_buffer or arg.type.is_memoryviewslice:
2500 2501 2502 2503
                if arg.or_none:
                    arg.accept_none = True
                elif arg.not_none:
                    arg.accept_none = False
2504
                elif (arg.type.is_extension_type or arg.type.is_builtin_type
2505
                      or arg.type.is_buffer or arg.type.is_memoryviewslice):
2506 2507 2508 2509 2510 2511
                    if arg.default and arg.default.constant_result is None:
                        # special case: def func(MyType obj = None)
                        arg.accept_none = True
                    else:
                        # default depends on compiler directive
                        arg.accept_none = allow_none_for_extension_args
2512 2513 2514
                else:
                    # probably just a plain 'object'
                    arg.accept_none = True
2515
            else:
2516
                arg.accept_none = True # won't be used, but must be there
2517
                if arg.not_none:
2518
                    error(arg.pos, "Only Python type arguments can have 'not None'")
2519
                if arg.or_none:
2520
                    error(arg.pos, "Only Python type arguments can have 'or None'")
2521

2522 2523
        env.fused_to_specific = f2s

William Stein's avatar
William Stein committed
2524
    def analyse_signature(self, env):
2525
        if self.entry.is_special:
2526
            if self.decorators:
2527
                error(self.pos, "special functions of cdef classes cannot have decorators")
2528 2529 2530 2531
            self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
        elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
            # Use the simpler calling signature for zero- and one-argument functions.
            if self.entry.signature is TypeSlots.pyfunction_signature:
2532 2533
                if len(self.args) == 0:
                    self.entry.signature = TypeSlots.pyfunction_noargs
2534 2535 2536
                elif len(self.args) == 1:
                    if self.args[0].default is None and not self.args[0].kw_only:
                        self.entry.signature = TypeSlots.pyfunction_onearg
2537 2538 2539
            elif self.entry.signature is TypeSlots.pymethod_signature:
                if len(self.args) == 1:
                    self.entry.signature = TypeSlots.unaryfunc
2540 2541 2542
                elif len(self.args) == 2:
                    if self.args[1].default is None and not self.args[1].kw_only:
                        self.entry.signature = TypeSlots.ibinaryfunc
2543

William Stein's avatar
William Stein committed
2544 2545
        sig = self.entry.signature
        nfixed = sig.num_fixed_args()
2546 2547 2548 2549 2550 2551 2552 2553 2554
        if sig is TypeSlots.pymethod_signature and nfixed == 1 \
               and len(self.args) == 0 and self.star_arg:
            # this is the only case where a diverging number of
            # arguments is not an error - when we have no explicit
            # 'self' parameter as in method(*args)
            sig = self.entry.signature = TypeSlots.pyfunction_signature # self is not 'really' used
            self.self_in_stararg = 1
            nfixed = 0

2555 2556 2557 2558 2559 2560 2561 2562 2563
        if self.is_staticmethod and env.is_c_class_scope:
            nfixed = 0
            self.self_in_stararg = True

            self.entry.signature = sig = copy.copy(sig)
            sig.fixed_arg_format = "*"
            sig.is_staticmethod = True
            sig.has_generic_args = True

2564 2565
        if ((self.is_classmethod or self.is_staticmethod) and
            self.has_fused_arguments and env.is_c_class_scope):
2566 2567
            del self.decorator_indirection.stats[:]

2568 2569 2570 2571 2572 2573 2574
        for i in range(min(nfixed, len(self.args))):
            arg = self.args[i]
            arg.is_generic = 0
            if sig.is_self_arg(i) and not self.is_staticmethod:
                if self.is_classmethod:
                    arg.is_type_arg = 1
                    arg.hdr_type = arg.type = Builtin.type_type
William Stein's avatar
William Stein committed
2575
                else:
2576 2577 2578
                    arg.is_self_arg = 1
                    arg.hdr_type = arg.type = env.parent_type
                arg.needs_conversion = 0
William Stein's avatar
William Stein committed
2579
            else:
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
                arg.hdr_type = sig.fixed_arg_type(i)
                if not arg.type.same_as(arg.hdr_type):
                    if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
                        arg.needs_type_test = 1
                    else:
                        arg.needs_conversion = 1
            if arg.needs_conversion:
                arg.hdr_cname = Naming.arg_prefix + arg.name
            else:
                arg.hdr_cname = Naming.var_prefix + arg.name

        if nfixed > len(self.args):
            self.bad_signature()
            return
        elif nfixed < len(self.args):
William Stein's avatar
William Stein committed
2595 2596 2597
            if not sig.has_generic_args:
                self.bad_signature()
            for arg in self.args:
Robert Bradshaw's avatar
Robert Bradshaw committed
2598 2599
                if arg.is_generic and \
                        (arg.type.is_extension_type or arg.type.is_builtin_type):
William Stein's avatar
William Stein committed
2600
                    arg.needs_type_test = 1
2601

William Stein's avatar
William Stein committed
2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
    def bad_signature(self):
        sig = self.entry.signature
        expected_str = "%d" % sig.num_fixed_args()
        if sig.has_generic_args:
            expected_str = expected_str + " or more"
        name = self.name
        if name.startswith("__") and name.endswith("__"):
            desc = "Special method"
        else:
            desc = "Method"
        error(self.pos,
            "%s %s has wrong number of arguments "
            "(%d declared, %s expected)" % (
                desc, self.name, len(self.args), expected_str))
2616

William Stein's avatar
William Stein committed
2617
    def declare_pyfunction(self, env):
2618 2619
        #print "DefNode.declare_pyfunction:", self.name, "in", env ###
        name = self.name
Stefan Behnel's avatar
Stefan Behnel committed
2620
        entry = env.lookup_here(name)
2621 2622
        if entry:
            if entry.is_final_cmethod and not env.parent_type.is_final_type:
Stefan Behnel's avatar
Stefan Behnel committed
2623
                error(self.pos, "Only final types can have final Python (def/cpdef) methods")
2624 2625 2626
            if (entry.type.is_cfunction and not entry.is_builtin_cmethod
                and not self.is_wrapper):
                warning(self.pos, "Overriding cdef method with def method.", 5)
2627
        entry = env.declare_pyfunction(name, self.pos, allow_redefine=not self.is_wrapper)
2628
        self.entry = entry
2629
        prefix = env.next_id(env.scope_prefix)
2630
        self.entry.pyfunc_cname = Naming.pyfunc_prefix + prefix + name
2631 2632
        if Options.docstrings:
            entry.doc = embed_position(self.pos, self.doc)
2633
            entry.doc_cname = Naming.funcdoc_prefix + prefix + name
2634
            if entry.is_special:
2635
                if entry.name in TypeSlots.invisible or not entry.doc or (entry.name in '__getattr__' and env.directives['fast_getattr']):
2636 2637 2638
                    entry.wrapperbase_cname = None
                else:
                    entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
2639 2640
        else:
            entry.doc = None
2641

Stefan Behnel's avatar
Stefan Behnel committed
2642
    def declare_lambda_function(self, env):
2643
        entry = env.declare_lambda_function(self.lambda_name, self.pos)
Stefan Behnel's avatar
Stefan Behnel committed
2644 2645
        entry.doc = None
        self.entry = entry
2646
        self.entry.pyfunc_cname = entry.cname
Stefan Behnel's avatar
Stefan Behnel committed
2647

William Stein's avatar
William Stein committed
2648 2649 2650 2651 2652 2653 2654 2655 2656 2657
    def declare_arguments(self, env):
        for arg in self.args:
            if not arg.name:
                error(arg.pos, "Missing argument name")
            if arg.needs_conversion:
                arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
                if arg.type.is_pyobject:
                    arg.entry.init = "0"
            else:
                arg.entry = self.declare_argument(env, arg)
2658
            arg.entry.is_arg = 1
2659
            arg.entry.used = 1
William Stein's avatar
William Stein committed
2660 2661 2662 2663 2664 2665
            arg.entry.is_self_arg = arg.is_self_arg
        self.declare_python_arg(env, self.star_arg)
        self.declare_python_arg(env, self.starstar_arg)

    def declare_python_arg(self, env, arg):
        if arg:
2666
            if env.directives['infer_types'] != False:
2667 2668 2669 2670
                type = PyrexTypes.unspecified_type
            else:
                type = py_object_type
            entry = env.declare_var(arg.name, type, arg.pos)
2671
            entry.is_arg = 1
2672 2673 2674 2675
            entry.used = 1
            entry.init = "0"
            entry.xdecref_cleanup = 1
            arg.entry = entry
2676

William Stein's avatar
William Stein committed
2677
    def analyse_expressions(self, env):
2678
        self.local_scope.directives = env.directives
William Stein's avatar
William Stein committed
2679
        self.analyse_default_values(env)
2680

2681
        if not self.needs_assignment_synthesis(env) and self.decorators:
2682 2683
            for decorator in self.decorators[::-1]:
                decorator.decorator.analyse_expressions(env)
2684

2685 2686
        self.py_wrapper.prepare_argument_coercion(env)

2687
    def needs_assignment_synthesis(self, env, code=None):
2688
        if self.is_wrapper or self.specialized_cpdefs or self.entry.is_fused_specialized:
2689
            return False
2690
        if self.is_staticmethod:
2691
            return True
2692 2693
        if self.no_assignment_synthesis:
            return False
2694
        # Should enable for module level as well, that will require more testing...
2695
        if self.entry.is_anonymous:
2696
            return True
2697 2698 2699 2700 2701 2702 2703
        if env.is_module_scope:
            if code is None:
                return env.directives['binding']
            else:
                return code.globalstate.directives['binding']
        return env.is_py_class_scope or env.is_closure_scope

2704 2705 2706 2707 2708 2709 2710
    def error_value(self):
        return self.entry.signature.error_value

    def caller_will_check_exceptions(self):
        return 1

    def generate_function_definitions(self, env, code):
2711 2712 2713
        if self.defaults_getter:
            self.defaults_getter.generate_function_definitions(env, code)

2714 2715 2716 2717 2718 2719 2720
        # Before closure cnames are mangled
        if self.py_wrapper_required:
            # func_cname might be modified by @cname
            self.py_wrapper.func_cname = self.entry.func_cname
            self.py_wrapper.generate_function_definitions(env, code)
        FuncDefNode.generate_function_definitions(self, env, code)

2721
    def generate_function_header(self, code, with_pymethdef, proto_only=0):
2722 2723 2724 2725 2726
        if proto_only:
            if self.py_wrapper_required:
                self.py_wrapper.generate_function_header(
                    code, with_pymethdef, True)
            return
William Stein's avatar
William Stein committed
2727
        arg_code_list = []
2728
        if self.entry.signature.has_dummy_arg:
2729
            if self.needs_outer_scope:
2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
                self_arg = 'PyObject *%s' % Naming.self_cname
            else:
                self_arg = 'CYTHON_UNUSED PyObject *%s' % Naming.self_cname
            arg_code_list.append(self_arg)

        def arg_decl_code(arg):
            entry = arg.entry
            if entry.in_closure:
                cname = entry.original_cname
            else:
                cname = entry.cname
2741
            decl = entry.type.declaration_code(cname)
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
            if entry.cf_used:
                return decl
            return 'CYTHON_UNUSED ' + decl

        for arg in self.args:
            arg_code_list.append(arg_decl_code(arg))
        if self.star_arg:
            arg_code_list.append(arg_decl_code(self.star_arg))
        if self.starstar_arg:
            arg_code_list.append(arg_decl_code(self.starstar_arg))
        arg_code = ', '.join(arg_code_list)
        dc = self.return_type.declaration_code(self.entry.pyfunc_cname)

        decls_code = code.globalstate['decls']
        preprocessor_guard = self.get_preprocessor_guard()
        if preprocessor_guard:
            decls_code.putln(preprocessor_guard)
        decls_code.putln(
            "static %s(%s); /* proto */" % (dc, arg_code))
        if preprocessor_guard:
            decls_code.putln("#endif")
        code.putln("static %s(%s) {" % (dc, arg_code))

    def generate_argument_declarations(self, env, code):
        pass

    def generate_keyword_list(self, code):
        pass

    def generate_argument_parsing_code(self, env, code):
        # Move arguments into closure if required
        def put_into_closure(entry):
            if entry.in_closure:
                code.putln('%s = %s;' % (entry.cname, entry.original_cname))
                code.put_var_incref(entry)
                code.put_var_giveref(entry)
        for arg in self.args:
            put_into_closure(arg.entry)
        for arg in self.star_arg, self.starstar_arg:
            if arg:
                put_into_closure(arg.entry)

    def generate_argument_type_tests(self, code):
        pass


class DefNodeWrapper(FuncDefNode):
    # DefNode python wrapper code generator

    defnode = None
    target = None # Target DefNode

    def __init__(self, *args, **kwargs):
        FuncDefNode.__init__(self, *args, **kwargs)
        self.num_kwonly_args = self.target.num_kwonly_args
        self.num_required_kw_args = self.target.num_required_kw_args
        self.num_required_args = self.target.num_required_args
        self.self_in_stararg = self.target.self_in_stararg
        self.signature = None

    def analyse_declarations(self, env):
        target_entry = self.target.entry
        name = self.name
        prefix = env.next_id(env.scope_prefix)
        target_entry.func_cname = Naming.pywrap_prefix + prefix + name
        target_entry.pymethdef_cname = Naming.pymethdef_prefix + prefix + name

        self.signature = target_entry.signature

2811
    def prepare_argument_coercion(self, env):
2812 2813 2814 2815 2816 2817 2818 2819 2820
        # This is only really required for Cython utility code at this time,
        # everything else can be done during code generation.  But we expand
        # all utility code here, simply because we cannot easily distinguish
        # different code types.
        for arg in self.args:
            if not arg.type.is_pyobject:
                if not arg.type.create_from_py_utility_code(env):
                    pass # will fail later

2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
    def signature_has_nongeneric_args(self):
        argcount = len(self.args)
        if argcount == 0 or (
                argcount == 1 and (self.args[0].is_self_arg or
                                   self.args[0].is_type_arg)):
            return 0
        return 1

    def signature_has_generic_args(self):
        return self.signature.has_generic_args

    def generate_function_body(self, code):
        args = []
        if self.signature.has_dummy_arg:
            args.append(Naming.self_cname)
        for arg in self.args:
2837 2838 2839
            if arg.hdr_type and not (arg.type.is_memoryviewslice or
                                     arg.type.is_struct or
                                     arg.type.is_complex):
2840 2841 2842
                args.append(arg.type.cast_code(arg.entry.cname))
            else:
                args.append(arg.entry.cname)
2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864
        if self.star_arg:
            args.append(self.star_arg.entry.cname)
        if self.starstar_arg:
            args.append(self.starstar_arg.entry.cname)
        args = ', '.join(args)
        if not self.return_type.is_void:
            code.put('%s = ' % Naming.retval_cname)
        code.putln('%s(%s);' % (
            self.target.entry.pyfunc_cname, args))

    def generate_function_definitions(self, env, code):
        lenv = self.target.local_scope
        # Generate C code for header and body of function
        code.putln("")
        code.putln("/* Python wrapper */")
        preprocessor_guard = self.target.get_preprocessor_guard()
        if preprocessor_guard:
            code.putln(preprocessor_guard)

        code.enter_cfunc_scope()
        code.return_from_error_cleanup_label = code.new_label()

Vitja Makarov's avatar
Vitja Makarov committed
2865
        with_pymethdef = (self.target.needs_assignment_synthesis(env, code) or
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894
                          self.target.pymethdef_required)
        self.generate_function_header(code, with_pymethdef)
        self.generate_argument_declarations(lenv, code)
        tempvardecl_code = code.insertion_point()

        if self.return_type.is_pyobject:
            retval_init = ' = 0'
        else:
            retval_init = ''
        if not self.return_type.is_void:
            code.putln('%s%s;' % (
                self.return_type.declaration_code(Naming.retval_cname),
                retval_init))
        code.put_declare_refcount_context()
        code.put_setup_refcount_context('%s (wrapper)' % self.name)

        self.generate_argument_parsing_code(lenv, code)
        self.generate_argument_type_tests(code)
        self.generate_function_body(code)

        # ----- Go back and insert temp variable declarations
        tempvardecl_code.put_temp_declarations(code.funcstate)

        # ----- Error cleanup
        if code.error_label in code.labels_used:
            code.put_goto(code.return_label)
            code.put_label(code.error_label)
            for cname, type in code.funcstate.all_managed_temps():
                code.put_xdecref(cname, type)
2895 2896 2897
            err_val = self.error_value()
            if err_val is not None:
                code.putln("%s = %s;" % (Naming.retval_cname, err_val))
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916

        # ----- Non-error return cleanup
        code.put_label(code.return_label)
        for entry in lenv.var_entries:
            if entry.is_arg and entry.type.is_pyobject:
                code.put_var_decref(entry)

        code.put_finish_refcount_context()
        if not self.return_type.is_void:
            code.putln("return %s;" % Naming.retval_cname)
        code.putln('}')
        code.exit_cfunc_scope()
        if preprocessor_guard:
            code.putln("#endif /*!(%s)*/" % preprocessor_guard)

    def generate_function_header(self, code, with_pymethdef, proto_only=0):
        arg_code_list = []
        sig = self.signature

2917
        if sig.has_dummy_arg or self.self_in_stararg:
2918 2919 2920 2921
            arg_code = "PyObject *%s" % Naming.self_cname
            if not sig.has_dummy_arg:
                arg_code = 'CYTHON_UNUSED ' + arg_code
            arg_code_list.append(arg_code)
2922

William Stein's avatar
William Stein committed
2923 2924
        for arg in self.args:
            if not arg.is_generic:
2925
                if arg.is_self_arg or arg.is_type_arg:
William Stein's avatar
William Stein committed
2926 2927
                    arg_code_list.append("PyObject *%s" % arg.hdr_cname)
                else:
2928 2929 2930 2931
                    arg_code_list.append(
                        arg.hdr_type.declaration_code(arg.hdr_cname))
        entry = self.target.entry
        if not entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
2932
            arg_code_list.append("CYTHON_UNUSED PyObject *unused")
2933
        if entry.scope.is_c_class_scope and entry.name == "__ipow__":
Lisandro Dalcin's avatar
Lisandro Dalcin committed
2934
            arg_code_list.append("CYTHON_UNUSED PyObject *unused")
William Stein's avatar
William Stein committed
2935 2936 2937 2938 2939
        if sig.has_generic_args:
            arg_code_list.append(
                "PyObject *%s, PyObject *%s"
                    % (Naming.args_cname, Naming.kwds_cname))
        arg_code = ", ".join(arg_code_list)
2940 2941
        dc = self.return_type.declaration_code(entry.func_cname)
        header = "static %s(%s)" % (dc, arg_code)
William Stein's avatar
William Stein committed
2942
        code.putln("%s; /*proto*/" % header)
2943

2944
        if proto_only:
2945
            if self.target.fused_py_func:
2946 2947 2948
                # If we are the specialized version of the cpdef, we still
                # want the prototype for the "fused cpdef", in case we're
                # checking to see if our method was overridden in Python
2949
                self.target.fused_py_func.generate_function_header(
2950
                                    code, with_pymethdef, proto_only=True)
2951
            return
2952

2953 2954 2955 2956
        if (Options.docstrings and entry.doc and
                not self.target.fused_py_func and
                not entry.scope.is_property_scope and
                (not entry.is_special or entry.wrapperbase_cname)):
2957
            # h_code = code.globalstate['h_code']
2958
            docstr = entry.doc
2959

Stefan Behnel's avatar
Stefan Behnel committed
2960
            if docstr.is_unicode:
2961
                docstr = docstr.utf8encode()
2962

William Stein's avatar
William Stein committed
2963 2964
            code.putln(
                'static char %s[] = "%s";' % (
2965
                    entry.doc_cname,
2966
                    split_string_literal(escape_byte_string(docstr))))
2967

2968
            if entry.is_special:
2969
                code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
2970
                code.putln(
2971
                    "struct wrapperbase %s;" % entry.wrapperbase_cname)
2972
                code.putln('#endif')
2973

2974
        if with_pymethdef or self.target.fused_py_func:
William Stein's avatar
William Stein committed
2975
            code.put(
2976
                "static PyMethodDef %s = " %
2977 2978
                    entry.pymethdef_cname)
            code.put_pymethoddef(self.target.entry, ";", allow_skip=False)
William Stein's avatar
William Stein committed
2979 2980 2981 2982
        code.putln("%s {" % header)

    def generate_argument_declarations(self, env, code):
        for arg in self.args:
2983
            if arg.is_generic:
2984 2985
                if arg.needs_conversion:
                    code.putln("PyObject *%s = 0;" % arg.hdr_cname)
2986
                else:
2987
                    code.put_var_declaration(arg.entry)
2988 2989 2990
        for entry in env.var_entries:
            if entry.is_arg:
                code.put_var_declaration(entry)
2991

2992
    def generate_argument_parsing_code(self, env, code):
Stefan Behnel's avatar
Stefan Behnel committed
2993 2994
        # Generate fast equivalent of PyArg_ParseTuple call for
        # generic arguments, if any, including args/kwargs
2995 2996
        old_error_label = code.new_error_label()
        our_error_label = code.error_label
Stefan Behnel's avatar
Stefan Behnel committed
2997
        end_label = code.new_label("argument_unpacking_done")
2998

2999 3000 3001
        has_kwonly_args = self.num_kwonly_args > 0
        has_star_or_kw_args = self.star_arg is not None \
            or self.starstar_arg is not None or has_kwonly_args
3002

3003
        for arg in self.args:
3004
            if not arg.type.is_pyobject:
3005 3006
                if not arg.type.create_from_py_utility_code(env):
                    pass # will fail later
3007

3008
        if not self.signature_has_generic_args():
3009 3010
            if has_star_or_kw_args:
                error(self.pos, "This method cannot have * or keyword arguments")
3011
            self.generate_argument_conversion_code(code)
3012

3013 3014
        elif not self.signature_has_nongeneric_args():
            # func(*args) or func(**kw) or func(*args, **kw)
3015
            self.generate_stararg_copy_code(code)
3016

3017
        else:
3018
            self.generate_tuple_and_keyword_parsing_code(self.args, end_label, code)
3019

3020 3021
        code.error_label = old_error_label
        if code.label_used(our_error_label):
3022 3023
            if not code.label_used(end_label):
                code.put_goto(end_label)
3024 3025 3026 3027 3028
            code.put_label(our_error_label)
            if has_star_or_kw_args:
                self.generate_arg_decref(self.star_arg, code)
                if self.starstar_arg:
                    if self.starstar_arg.entry.xdecref_cleanup:
3029
                        code.put_var_xdecref_clear(self.starstar_arg.entry)
3030
                    else:
3031
                        code.put_var_decref_clear(self.starstar_arg.entry)
3032
            code.put_add_traceback(self.target.entry.qualified_name)
3033
            code.put_finish_refcount_context()
3034
            code.putln("return %s;" % self.error_value())
3035
        if code.label_used(end_label):
3036 3037
            code.put_label(end_label)

William Stein's avatar
William Stein committed
3038 3039
    def generate_arg_xdecref(self, arg, code):
        if arg:
3040
            code.put_var_xdecref_clear(arg.entry)
3041

3042 3043
    def generate_arg_decref(self, arg, code):
        if arg:
3044
            code.put_var_decref_clear(arg.entry)
William Stein's avatar
William Stein committed
3045

3046 3047
    def generate_stararg_copy_code(self, code):
        if not self.star_arg:
3048 3049
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3050 3051 3052
            code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
                       Naming.args_cname)
            code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
Stefan Behnel's avatar
Stefan Behnel committed
3053
                    self.name, Naming.args_cname, self.error_value()))
3054
            code.putln("}")
3055

3056 3057 3058 3059 3060 3061 3062 3063
        if self.starstar_arg:
            if self.star_arg:
                kwarg_check = "unlikely(%s)" % Naming.kwds_cname
            else:
                kwarg_check = "%s" % Naming.kwds_cname
        else:
            kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
                Naming.kwds_cname, Naming.kwds_cname)
3064 3065
        code.globalstate.use_utility_code(
            UtilityCode.load_cached("KeywordStringCheck", "FunctionArguments.c"))
3066
        code.putln(
3067 3068
            "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
                kwarg_check, Naming.kwds_cname, self.name,
3069
                bool(self.starstar_arg), self.error_value()))
3070

3071
        if self.starstar_arg:
3072
            code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
3073 3074 3075
                    self.starstar_arg.entry.cname,
                    Naming.kwds_cname,
                    Naming.kwds_cname))
3076 3077
            code.putln("if (unlikely(!%s)) return %s;" % (
                    self.starstar_arg.entry.cname, self.error_value()))
3078
            self.starstar_arg.entry.xdecref_cleanup = 0
3079
            code.put_gotref(self.starstar_arg.entry.cname)
3080

3081 3082 3083 3084 3085 3086 3087 3088
        if self.self_in_stararg:
            # need to create a new tuple with 'self' inserted as first item
            code.put("%s = PyTuple_New(PyTuple_GET_SIZE(%s)+1); if (unlikely(!%s)) " % (
                    self.star_arg.entry.cname,
                    Naming.args_cname,
                    self.star_arg.entry.cname))
            if self.starstar_arg:
                code.putln("{")
3089
                code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111
                code.putln("return %s;" % self.error_value())
                code.putln("}")
            else:
                code.putln("return %s;" % self.error_value())
            code.put_gotref(self.star_arg.entry.cname)
            code.put_incref(Naming.self_cname, py_object_type)
            code.put_giveref(Naming.self_cname)
            code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % (
                self.star_arg.entry.cname, Naming.self_cname))
            temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
            code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % (
                temp, temp, Naming.args_cname, temp))
            code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % (
                Naming.args_cname, temp))
            code.put_incref("item", py_object_type)
            code.put_giveref("item")
            code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % (
                self.star_arg.entry.cname, temp))
            code.putln("}")
            code.funcstate.release_temp(temp)
            self.star_arg.entry.xdecref_cleanup = 0
        elif self.star_arg:
3112 3113 3114 3115 3116 3117
            code.put_incref(Naming.args_cname, py_object_type)
            code.putln("%s = %s;" % (
                    self.star_arg.entry.cname,
                    Naming.args_cname))
            self.star_arg.entry.xdecref_cleanup = 0

3118
    def generate_tuple_and_keyword_parsing_code(self, args, success_label, code):
3119
        argtuple_error_label = code.new_label("argtuple_error")
3120

3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140
        positional_args = []
        required_kw_only_args = []
        optional_kw_only_args = []
        for arg in args:
            if arg.is_generic:
                if arg.default:
                    if not arg.is_self_arg and not arg.is_type_arg:
                        if arg.kw_only:
                            optional_kw_only_args.append(arg)
                        else:
                            positional_args.append(arg)
                elif arg.kw_only:
                    required_kw_only_args.append(arg)
                elif not arg.is_self_arg and not arg.is_type_arg:
                    positional_args.append(arg)

        # sort required kw-only args before optional ones to avoid special
        # cases in the unpacking code
        kw_only_args = required_kw_only_args + optional_kw_only_args

3141
        min_positional_args = self.num_required_args - self.num_required_kw_args
3142
        if len(args) > 0 and (args[0].is_self_arg or args[0].is_type_arg):
3143 3144
            min_positional_args -= 1
        max_positional_args = len(positional_args)
3145 3146
        has_fixed_positional_count = not self.star_arg and \
            min_positional_args == max_positional_args
3147
        has_kw_only_args = bool(kw_only_args)
3148

Stefan Behnel's avatar
Stefan Behnel committed
3149
        if self.num_required_kw_args:
3150 3151
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c"))
Stefan Behnel's avatar
Stefan Behnel committed
3152

3153 3154 3155
        if self.starstar_arg or self.star_arg:
            self.generate_stararg_init_code(max_positional_args, code)

3156 3157
        code.putln('{')
        all_args = tuple(positional_args) + tuple(kw_only_args)
3158 3159 3160 3161
        code.putln("static PyObject **%s[] = {%s,0};" % (
            Naming.pykwdlist_cname,
            ','.join([ '&%s' % code.intern_identifier(arg.name)
                        for arg in all_args ])))
3162 3163 3164 3165 3166 3167 3168 3169 3170 3171

        # Before being converted and assigned to the target variables,
        # borrowed references to all unpacked argument values are
        # collected into a local PyObject* array called "values",
        # regardless if they were taken from default arguments,
        # positional arguments or keyword arguments.  Note that
        # C-typed default arguments are handled at conversion time,
        # so their array value is NULL in the end if no argument
        # was passed for them.
        self.generate_argument_values_setup_code(all_args, code)
3172

3173
        # --- optimised code when we receive keyword arguments
3174 3175 3176
        code.putln("if (%s(%s)) {" % (
            (self.num_required_kw_args > 0) and "likely" or "unlikely",
            Naming.kwds_cname))
3177 3178
        self.generate_keyword_unpacking_code(
            min_positional_args, max_positional_args,
3179 3180
            has_fixed_positional_count, has_kw_only_args,
            all_args, argtuple_error_label, code)
3181 3182

        # --- optimised code when we do not receive any keyword arguments
3183
        if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
3184 3185 3186 3187 3188 3189 3190 3191 3192
            # Python raises arg tuple related errors first, so we must
            # check the length here
            if min_positional_args == max_positional_args and not self.star_arg:
                compare = '!='
            else:
                compare = '<'
            code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
                    Naming.args_cname, compare, min_positional_args))
            code.put_goto(argtuple_error_label)
3193

3194 3195 3196 3197 3198 3199 3200 3201 3202
        if self.num_required_kw_args:
            # pure error case: keywords required but not passed
            if max_positional_args > min_positional_args and not self.star_arg:
                code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % (
                        Naming.args_cname, max_positional_args))
                code.put_goto(argtuple_error_label)
            code.putln('} else {')
            for i, arg in enumerate(kw_only_args):
                if not arg.default:
3203
                    pystring_cname = code.intern_identifier(arg.name)
3204
                    # required keyword-only argument missing
3205
                    code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
Stefan Behnel's avatar
Stefan Behnel committed
3206
                            self.name,
3207
                            pystring_cname))
3208 3209
                    code.putln(code.error_goto(self.pos))
                    break
3210

3211
        else:
3212
            # optimised tuple unpacking code
3213
            code.putln('} else {')
3214 3215 3216 3217 3218
            if min_positional_args == max_positional_args:
                # parse the exact number of positional arguments from
                # the args tuple
                for i, arg in enumerate(positional_args):
                    code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
3219
            else:
3220 3221 3222 3223 3224 3225 3226 3227
                # parse the positional arguments from the variable length
                # args tuple and reject illegal argument tuple sizes
                code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
                if self.star_arg:
                    code.putln('default:')
                reversed_args = list(enumerate(positional_args))[::-1]
                for i, arg in reversed_args:
                    if i >= min_positional_args-1:
3228
                        code.put('case %2d: ' % (i+1))
3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239
                    code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i))
                if min_positional_args == 0:
                    code.put('case  0: ')
                code.putln('break;')
                if self.star_arg:
                    if min_positional_args:
                        for i in range(min_positional_args-1, -1, -1):
                            code.putln('case %2d:' % i)
                        code.put_goto(argtuple_error_label)
                else:
                    code.put('default: ')
3240
                    code.put_goto(argtuple_error_label)
3241 3242
                code.putln('}')

3243
        code.putln('}') # end of the conditional unpacking blocks
3244

3245 3246 3247
        # Convert arg values to their final type and assign them.
        # Also inject non-Python default arguments, which do cannot
        # live in the values[] array.
3248 3249
        for i, arg in enumerate(all_args):
            self.generate_arg_assignment(arg, "values[%d]" % i, code)
3250

3251
        code.putln('}') # end of the whole argument unpacking block
3252 3253 3254 3255

        if code.label_used(argtuple_error_label):
            code.put_goto(success_label)
            code.put_label(argtuple_error_label)
3256 3257
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3258
            code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
Stefan Behnel's avatar
Stefan Behnel committed
3259
                    self.name, has_fixed_positional_count,
3260 3261 3262 3263
                    min_positional_args, max_positional_args,
                    Naming.args_cname))
            code.putln(code.error_goto(self.pos))

3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
    def generate_arg_assignment(self, arg, item, code):
        if arg.type.is_pyobject:
            # Python default arguments were already stored in 'item' at the very beginning
            if arg.is_generic:
                item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
            entry = arg.entry
            code.putln("%s = %s;" % (entry.cname, item))
        else:
            func = arg.type.from_py_function
            if func:
                if arg.default:
                    # C-typed default arguments must be handled here
                    code.putln('if (%s) {' % item)
                rhs = "%s(%s)" % (func, item)
                if arg.type.is_enum:
                    rhs = arg.type.cast_code(rhs)
                code.putln("%s = %s; %s" % (
                    arg.entry.cname,
                    rhs,
                    code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
                if arg.default:
                    code.putln('} else {')
                    code.putln(
                        "%s = %s;" % (
                            arg.entry.cname,
                            arg.calculate_default_value_code(code)))
                    if arg.type.is_memoryviewslice:
                        code.put_incref_memoryviewslice(arg.entry.cname,
                                                        have_gil=True)
                    code.putln('}')
            else:
                error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
3296

3297
    def generate_stararg_init_code(self, max_positional_args, code):
3298
        if self.starstar_arg:
3299
            self.starstar_arg.entry.xdecref_cleanup = 0
Stefan Behnel's avatar
Stefan Behnel committed
3300 3301 3302 3303
            code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % (
                    self.starstar_arg.entry.cname,
                    self.starstar_arg.entry.cname,
                    self.error_value()))
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
3304
            code.put_gotref(self.starstar_arg.entry.cname)
Stefan Behnel's avatar
Stefan Behnel committed
3305 3306 3307 3308 3309
        if self.star_arg:
            self.star_arg.entry.xdecref_cleanup = 0
            code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
                    Naming.args_cname,
                    max_positional_args))
3310
            code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % (
Stefan Behnel's avatar
Stefan Behnel committed
3311 3312
                    self.star_arg.entry.cname, Naming.args_cname,
                    max_positional_args, Naming.args_cname))
3313
            code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
Stefan Behnel's avatar
Stefan Behnel committed
3314
            if self.starstar_arg:
3315
                code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
3316 3317 3318 3319
            code.put_finish_refcount_context()
            code.putln('return %s;' % self.error_value())
            code.putln('}')
            code.put_gotref(self.star_arg.entry.cname)
Stefan Behnel's avatar
Stefan Behnel committed
3320 3321 3322 3323
            code.putln('} else {')
            code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
            code.put_incref(Naming.empty_tuple, py_object_type)
            code.putln('}')
3324

3325
    def generate_argument_values_setup_code(self, args, code):
3326
        max_args = len(args)
Stefan Behnel's avatar
Stefan Behnel committed
3327 3328
        # the 'values' array collects borrowed references to arguments
        # before doing any type coercion etc.
3329
        code.putln("PyObject* values[%d] = {%s};" % (
Stefan Behnel's avatar
Stefan Behnel committed
3330
            max_args, ','.join('0'*max_args)))
3331

3332
        if self.target.defaults_struct:
3333
            code.putln('%s *%s = __Pyx_CyFunction_Defaults(%s, %s);' % (
3334 3335
                self.target.defaults_struct, Naming.dynamic_args_cname,
                self.target.defaults_struct, Naming.self_cname))
3336

3337 3338
        # assign borrowed Python default values to the values array,
        # so that they can be overwritten by received arguments below
3339
        for i, arg in enumerate(args):
3340 3341 3342 3343
            if arg.default and arg.type.is_pyobject:
                default_value = arg.calculate_default_value_code(code)
                code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value)))

3344 3345 3346 3347
    def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
                                        has_fixed_positional_count, has_kw_only_args,
                                        all_args, argtuple_error_label, code):
        code.putln('Py_ssize_t kw_args;')
3348
        code.putln('const Py_ssize_t pos_args = PyTuple_GET_SIZE(%s);' % Naming.args_cname)
3349
        # copy the values from the args tuple and check that it's not too long
3350
        code.putln('switch (pos_args) {')
Stefan Behnel's avatar
Stefan Behnel committed
3351 3352
        if self.star_arg:
            code.putln('default:')
3353
        for i in range(max_positional_args-1, -1, -1):
3354
            code.put('case %2d: ' % (i+1))
3355 3356
            code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
                    i, Naming.args_cname, i))
3357
        code.putln('case  0: break;')
3358
        if not self.star_arg:
Stefan Behnel's avatar
Stefan Behnel committed
3359
            code.put('default: ') # more arguments than allowed
3360
            code.put_goto(argtuple_error_label)
3361 3362
        code.putln('}')

3363 3364 3365 3366 3367 3368 3369 3370 3371
        # The code above is very often (but not always) the same as
        # the optimised non-kwargs tuple unpacking code, so we keep
        # the code block above at the very top, before the following
        # 'external' PyDict_Size() call, to make it easy for the C
        # compiler to merge the two separate tuple unpacking
        # implementations into one when they turn out to be identical.

        # If we received kwargs, fill up the positional/required
        # arguments with values from the kw dict
3372
        code.putln('kw_args = PyDict_Size(%s);' % Naming.kwds_cname)
3373
        if self.num_required_args or max_positional_args > 0:
Stefan Behnel's avatar
Stefan Behnel committed
3374 3375 3376 3377
            last_required_arg = -1
            for i, arg in enumerate(all_args):
                if not arg.default:
                    last_required_arg = i
3378 3379
            if last_required_arg < max_positional_args:
                last_required_arg = max_positional_args-1
Stefan Behnel's avatar
Stefan Behnel committed
3380
            if max_positional_args > 0:
3381
                code.putln('switch (pos_args) {')
3382
            for i, arg in enumerate(all_args[:last_required_arg+1]):
Stefan Behnel's avatar
Stefan Behnel committed
3383
                if max_positional_args > 0 and i <= max_positional_args:
3384 3385 3386 3387
                    if self.star_arg and i == max_positional_args:
                        code.putln('default:')
                    else:
                        code.putln('case %2d:' % i)
3388
                pystring_cname = code.intern_identifier(arg.name)
3389
                if arg.default:
3390
                    if arg.kw_only:
3391
                        # optional kw-only args are handled separately below
3392
                        continue
3393
                    code.putln('if (kw_args > 0) {')
3394
                    # don't overwrite default argument
3395
                    code.putln('PyObject* value = PyDict_GetItem(%s, %s);' % (
3396
                        Naming.kwds_cname, pystring_cname))
3397
                    code.putln('if (value) { values[%d] = value; kw_args--; }' % i)
3398 3399
                    code.putln('}')
                else:
3400
                    code.putln('if (likely((values[%d] = PyDict_GetItem(%s, %s)) != 0)) kw_args--;' % (
3401
                        i, Naming.kwds_cname, pystring_cname))
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411
                    if i < min_positional_args:
                        if i == 0:
                            # special case: we know arg 0 is missing
                            code.put('else ')
                            code.put_goto(argtuple_error_label)
                        else:
                            # print the correct number of values (args or
                            # kwargs) that were passed into positional
                            # arguments up to this point
                            code.putln('else {')
3412 3413
                            code.globalstate.use_utility_code(
                                UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c"))
3414
                            code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
Stefan Behnel's avatar
Stefan Behnel committed
3415
                                    self.name, has_fixed_positional_count,
3416 3417 3418 3419
                                    min_positional_args, max_positional_args, i))
                            code.putln(code.error_goto(self.pos))
                            code.putln('}')
                    elif arg.kw_only:
3420
                        code.putln('else {')
3421
                        code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
Stefan Behnel's avatar
Stefan Behnel committed
3422
                                self.name, pystring_cname))
3423 3424
                        code.putln(code.error_goto(self.pos))
                        code.putln('}')
Stefan Behnel's avatar
Stefan Behnel committed
3425 3426
            if max_positional_args > 0:
                code.putln('}')
3427

3428
        if has_kw_only_args:
3429
            # unpack optional keyword-only arguments separately because
3430
            # checking for interned strings in a dict is faster than iterating
3431
            self.generate_optional_kwonly_args_unpacking_code(all_args, code)
3432

3433
        code.putln('if (unlikely(kw_args > 0)) {')
3434 3435
        # non-positional/-required kw args left in dict: default args,
        # kw-only args, **kwargs or error
Stefan Behnel's avatar
Stefan Behnel committed
3436 3437 3438 3439 3440
        #
        # This is sort of a catch-all: except for checking required
        # arguments, this will always do the right thing for unpacking
        # keyword arguments, so that we can concentrate on optimising
        # common cases above.
3441 3442 3443
        if max_positional_args == 0:
            pos_arg_count = "0"
        elif self.star_arg:
3444 3445
            code.putln("const Py_ssize_t used_pos_args = (pos_args < %d) ? pos_args : %d;" % (
                    max_positional_args, max_positional_args))
Stefan Behnel's avatar
Stefan Behnel committed
3446 3447
            pos_arg_count = "used_pos_args"
        else:
3448
            pos_arg_count = "pos_args"
3449 3450
        code.globalstate.use_utility_code(
            UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c"))
Stefan Behnel's avatar
Stefan Behnel committed
3451 3452
        code.putln(
            'if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % (
Stefan Behnel's avatar
Stefan Behnel committed
3453 3454 3455 3456
                Naming.kwds_cname,
                Naming.pykwdlist_cname,
                self.starstar_arg and self.starstar_arg.entry.cname or '0',
                pos_arg_count,
Stefan Behnel's avatar
Stefan Behnel committed
3457 3458
                self.name,
                code.error_goto(self.pos)))
3459
        code.putln('}')
3460

3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
    def generate_optional_kwonly_args_unpacking_code(self, all_args, code):
        optional_args = []
        first_optional_arg = -1
        for i, arg in enumerate(all_args):
            if not arg.kw_only or not arg.default:
                continue
            if not optional_args:
                first_optional_arg = i
            optional_args.append(arg.name)
        if optional_args:
            if len(optional_args) > 1:
                # if we receive more than the named kwargs, we either have **kwargs
                # (in which case we must iterate anyway) or it's an error (which we
                # also handle during iteration) => skip this part if there are more
                code.putln('if (kw_args > 0 && %s(kw_args <= %d)) {' % (
                    not self.starstar_arg and 'likely' or '',
                    len(optional_args)))
                code.putln('Py_ssize_t index;')
                # not unrolling the loop here reduces the C code overhead
                code.putln('for (index = %d; index < %d && kw_args > 0; index++) {' % (
                    first_optional_arg, first_optional_arg + len(optional_args)))
            else:
                code.putln('if (kw_args == 1) {')
                code.putln('const Py_ssize_t index = %d;' % first_optional_arg)
            code.putln('PyObject* value = PyDict_GetItem(%s, *%s[index]);' % (
                Naming.kwds_cname, Naming.pykwdlist_cname))
            code.putln('if (value) { values[index] = value; kw_args--; }')
            if len(optional_args) > 1:
                code.putln('}')
            code.putln('}')

William Stein's avatar
William Stein committed
3492
    def generate_argument_conversion_code(self, code):
3493 3494 3495
        # Generate code to convert arguments from signature type to
        # declared type, if needed.  Also copies signature arguments
        # into closure fields.
William Stein's avatar
William Stein committed
3496 3497 3498 3499 3500 3501 3502 3503 3504
        for arg in self.args:
            if arg.needs_conversion:
                self.generate_arg_conversion(arg, code)

    def generate_arg_conversion(self, arg, code):
        # Generate conversion code for one argument.
        old_type = arg.hdr_type
        new_type = arg.type
        if old_type.is_pyobject:
Robert Bradshaw's avatar
Robert Bradshaw committed
3505 3506 3507 3508
            if arg.default:
                code.putln("if (%s) {" % arg.hdr_cname)
            else:
                code.putln("assert(%s); {" % arg.hdr_cname)
William Stein's avatar
William Stein committed
3509
            self.generate_arg_conversion_from_pyobject(arg, code)
Robert Bradshaw's avatar
Robert Bradshaw committed
3510
            code.putln("}")
William Stein's avatar
William Stein committed
3511 3512 3513 3514 3515 3516 3517 3518
        elif new_type.is_pyobject:
            self.generate_arg_conversion_to_pyobject(arg, code)
        else:
            if new_type.assignable_from(old_type):
                code.putln(
                    "%s = %s;" % (arg.entry.cname, arg.hdr_cname))
            else:
                error(arg.pos,
3519
                    "Cannot convert 1 argument from '%s' to '%s'" %
William Stein's avatar
William Stein committed
3520
                        (old_type, new_type))
3521

William Stein's avatar
William Stein committed
3522 3523 3524
    def generate_arg_conversion_from_pyobject(self, arg, code):
        new_type = arg.type
        func = new_type.from_py_function
3525
        # copied from CoerceFromPyTypeNode
William Stein's avatar
William Stein committed
3526
        if func:
3527 3528 3529 3530 3531
            lhs = arg.entry.cname
            rhs = "%s(%s)" % (func, arg.hdr_cname)
            if new_type.is_enum:
                rhs = PyrexTypes.typecast(new_type, PyrexTypes.c_long_type, rhs)
            code.putln("%s = %s; %s" % (
3532
                lhs,
3533
                rhs,
3534
                code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
William Stein's avatar
William Stein committed
3535
        else:
3536 3537
            error(arg.pos,
                "Cannot convert Python object argument to type '%s'"
William Stein's avatar
William Stein committed
3538
                    % new_type)
3539

William Stein's avatar
William Stein committed
3540 3541 3542 3543
    def generate_arg_conversion_to_pyobject(self, arg, code):
        old_type = arg.hdr_type
        func = old_type.to_py_function
        if func:
Robert Bradshaw's avatar
Robert Bradshaw committed
3544
            code.putln("%s = %s(%s); %s" % (
William Stein's avatar
William Stein committed
3545 3546 3547
                arg.entry.cname,
                func,
                arg.hdr_cname,
Robert Bradshaw's avatar
Robert Bradshaw committed
3548
                code.error_goto_if_null(arg.entry.cname, arg.pos)))
3549
            code.put_var_gotref(arg.entry)
William Stein's avatar
William Stein committed
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561
        else:
            error(arg.pos,
                "Cannot convert argument of type '%s' to Python object"
                    % old_type)

    def generate_argument_type_tests(self, code):
        # Generate type tests for args whose signature
        # type is PyObject * and whose declared type is
        # a subtype thereof.
        for arg in self.args:
            if arg.needs_type_test:
                self.generate_arg_type_test(arg, code)
3562 3563 3564
            elif not arg.accept_none and (arg.type.is_pyobject or
                                          arg.type.is_buffer or
                                          arg.type.is_memoryviewslice):
3565 3566
                self.generate_arg_none_check(arg, code)

William Stein's avatar
William Stein committed
3567
    def error_value(self):
3568
        return self.signature.error_value
3569

3570 3571 3572 3573 3574 3575 3576 3577 3578 3579

class GeneratorDefNode(DefNode):
    # Generator DefNode.
    #
    # gbody          GeneratorBodyDefNode
    #

    is_generator = True
    needs_closure = True

Stefan Behnel's avatar
Stefan Behnel committed
3580
    child_attrs = DefNode.child_attrs + ["gbody"]
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594

    def __init__(self, **kwargs):
        # XXX: don't actually needs a body
        kwargs['body'] = StatListNode(kwargs['pos'], stats=[])
        super(GeneratorDefNode, self).__init__(**kwargs)

    def analyse_declarations(self, env):
        super(GeneratorDefNode, self).analyse_declarations(env)
        self.gbody.local_scope = self.local_scope
        self.gbody.analyse_declarations(env)

    def generate_function_body(self, env, code):
        body_cname = self.gbody.entry.func_cname

3595 3596 3597 3598 3599 3600
        code.putln('{')
        code.putln('__pyx_GeneratorObject *gen = __Pyx_Generator_New('
                   '(__pyx_generator_body_t) %s, (PyObject *) %s); %s' % (
                       body_cname, Naming.cur_scope_cname,
                       code.error_goto_if_null('gen', self.pos)))
        code.put_decref(Naming.cur_scope_cname, py_object_type)
3601
        if self.requires_classobj:
3602
            classobj_cname = 'gen->classobj'
3603 3604 3605 3606
            code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
                classobj_cname, Naming.self_cname))
            code.put_incref(classobj_cname, py_object_type)
            code.put_giveref(classobj_cname)
3607
        code.put_finish_refcount_context()
3608 3609
        code.putln('return (PyObject *) gen;');
        code.putln('}')
3610 3611

    def generate_function_definitions(self, env, code):
Stefan Behnel's avatar
Stefan Behnel committed
3612
        env.use_utility_code(UtilityCode.load_cached("Generator", "Generator.c"))
3613

3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624
        self.gbody.generate_function_header(code, proto=True)
        super(GeneratorDefNode, self).generate_function_definitions(env, code)
        self.gbody.generate_function_definitions(env, code)


class GeneratorBodyDefNode(DefNode):
    # Generator body DefNode.
    #

    is_generator_body = True

3625
    def __init__(self, pos=None, name=None, body=None):
3626 3627 3628
        super(GeneratorBodyDefNode, self).__init__(
            pos=pos, body=body, name=name, doc=None,
            args=[], star_arg=None, starstar_arg=None)
3629

3630 3631
    def declare_generator_body(self, env):
        prefix = env.next_id(env.scope_prefix)
Vitja Makarov's avatar
Vitja Makarov committed
3632
        name = env.next_id('generator')
3633 3634 3635 3636
        cname = Naming.genbody_prefix + prefix + name
        entry = env.declare_var(None, py_object_type, self.pos,
                                cname=cname, visibility='private')
        entry.func_cname = cname
3637 3638 3639 3640 3641 3642
        entry.qualified_name = EncodedString(self.name)
        self.entry = entry

    def analyse_declarations(self, env):
        self.analyse_argument_types(env)
        self.declare_generator_body(env)
3643 3644

    def generate_function_header(self, code, proto=False):
3645
        header = "static PyObject *%s(__pyx_GeneratorObject *%s, PyObject *%s)" % (
3646
            self.entry.func_cname,
3647
            Naming.generator_cname,
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669
            Naming.sent_value_cname)
        if proto:
            code.putln('%s; /* proto */' % header)
        else:
            code.putln('%s /* generator body */\n{' % header);

    def generate_function_definitions(self, env, code):
        lenv = self.local_scope

        # Generate closure function definitions
        self.body.generate_function_definitions(lenv, code)

        # Generate C code for header and body of function
        code.enter_cfunc_scope()
        code.return_from_error_cleanup_label = code.new_label()

        # ----- Top-level constants used by this function
        code.mark_pos(self.pos)
        self.generate_cached_builtins_decls(lenv, code)
        # ----- Function header
        code.putln("")
        self.generate_function_header(code)
3670
        closure_init_code = code.insertion_point()
3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687
        # ----- Local variables
        code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
        tempvardecl_code = code.insertion_point()
        code.put_declare_refcount_context()
        code.put_setup_refcount_context(self.entry.name)

        # ----- Resume switch point.
        code.funcstate.init_closure_temps(lenv.scope_class.type.scope)
        resume_code = code.insertion_point()
        first_run_label = code.new_label('first_run')
        code.use_label(first_run_label)
        code.put_label(first_run_label)
        code.putln('%s' %
                   (code.error_goto_if_null(Naming.sent_value_cname, self.pos)))

        # ----- Function body
        self.generate_function_body(env, code)
3688 3689 3690 3691 3692 3693
        # ----- Closure initialization
        if lenv.scope_class.type.scope.entries:
            closure_init_code.putln('%s = %s;' % (
                lenv.scope_class.type.declaration_code(Naming.cur_scope_cname),
                lenv.scope_class.type.cast_code('%s->closure' %
                                                Naming.generator_cname)))
Stefan Behnel's avatar
Stefan Behnel committed
3694 3695
        # on normal generator termination, we do not take the exception propagation
        # path: no traceback info is required and not creating it is much faster
3696
        code.putln('PyErr_SetNone(PyExc_StopIteration);')
3697 3698 3699 3700 3701 3702
        # ----- Error cleanup
        if code.error_label in code.labels_used:
            code.put_goto(code.return_label)
            code.put_label(code.error_label)
            for cname, type in code.funcstate.all_managed_temps():
                code.put_xdecref(cname, type)
3703
            code.put_add_traceback(self.entry.qualified_name)
3704 3705 3706

        # ----- Non-error return cleanup
        code.put_label(code.return_label)
3707
        code.put_xdecref(Naming.retval_cname, py_object_type)
3708
        code.putln('%s->resume_label = -1;' % Naming.generator_cname)
3709 3710
        # clean up as early as possible to help breaking any reference cycles
        code.putln('__Pyx_Generator_clear((PyObject*)%s);' % Naming.generator_cname)
3711
        code.put_finish_refcount_context()
Stefan Behnel's avatar
Stefan Behnel committed
3712
        code.putln('return NULL;')
3713 3714 3715 3716 3717
        code.putln("}")

        # ----- Go back and insert temp variable declarations
        tempvardecl_code.put_temp_declarations(code.funcstate)
        # ----- Generator resume code
3718
        resume_code.putln("switch (%s->resume_label) {" % (
Stefan Behnel's avatar
Stefan Behnel committed
3719
                       Naming.generator_cname))
3720
        resume_code.putln("case 0: goto %s;" % first_run_label)
3721 3722 3723 3724 3725

        from ParseTreeTransforms import YieldNodeCollector
        collector = YieldNodeCollector()
        collector.visitchildren(self)
        for yield_expr in collector.yields:
3726
            resume_code.putln("case %d: goto %s;" % (
Stefan Behnel's avatar
Stefan Behnel committed
3727 3728
                yield_expr.label_num, yield_expr.label_name))
        resume_code.putln("default: /* CPython raises the right error here */")
3729
        resume_code.put_finish_refcount_context()
Stefan Behnel's avatar
Stefan Behnel committed
3730 3731
        resume_code.putln("return NULL;")
        resume_code.putln("}")
3732 3733 3734 3735

        code.exit_cfunc_scope()


3736 3737
class OverrideCheckNode(StatNode):
    # A Node for dispatching to the def method if it
3738
    # is overriden.
3739 3740 3741 3742 3743 3744
    #
    #  py_func
    #
    #  args
    #  func_temp
    #  body
3745

Robert Bradshaw's avatar
Robert Bradshaw committed
3746
    child_attrs = ['body']
3747

3748
    body = None
Robert Bradshaw's avatar
Robert Bradshaw committed
3749

3750 3751
    def analyse_expressions(self, env):
        self.args = env.arg_entries
3752 3753 3754 3755
        if self.py_func.is_module_scope:
            first_arg = 0
        else:
            first_arg = 1
3756
        import ExprNodes
3757
        self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
3758
        call_tuple = ExprNodes.TupleNode(self.pos, args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
3759
        call_node = ExprNodes.SimpleCallNode(self.pos,
3760
                                             function=self.func_node,
3761
                                             args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
3762 3763
        self.body = ReturnStatNode(self.pos, value=call_node)
        self.body.analyse_expressions(env)
3764

3765
    def generate_execution_code(self, code):
3766
        interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
3767
        # Check to see if we are an extension type
3768 3769 3770 3771
        if self.py_func.is_module_scope:
            self_arg = "((PyObject *)%s)" % Naming.module_cname
        else:
            self_arg = "((PyObject *)%s)" % self.args[0].cname
3772
        code.putln("/* Check if called by wrapper */")
3773
        code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
3774
        code.putln("/* Check if overriden in Python */")
3775 3776 3777
        if self.py_func.is_module_scope:
            code.putln("else {")
        else:
3778
            code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
3779 3780
        func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
        self.func_node.set_cname(func_node_temp)
3781
        # need to get attribute manually--scope would return cdef method
3782
        err = code.error_goto_if_null(func_node_temp, self.pos)
3783
        code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
3784 3785 3786
            func_node_temp, self_arg, interned_attr_cname, err))
        code.put_gotref(func_node_temp)
        is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
3787
        is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)%s)" % (
3788
            func_node_temp, self.py_func.entry.func_cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
3789
        code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden))
3790 3791
        self.body.generate_execution_code(code)
        code.putln("}")
3792 3793
        code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
        code.funcstate.release_temp(func_node_temp)
Robert Bradshaw's avatar
Robert Bradshaw committed
3794
        code.putln("}")
3795

Robert Bradshaw's avatar
Robert Bradshaw committed
3796 3797
class ClassDefNode(StatNode, BlockNode):
    pass
3798

Robert Bradshaw's avatar
Robert Bradshaw committed
3799
class PyClassDefNode(ClassDefNode):
William Stein's avatar
William Stein committed
3800 3801
    #  A Python class definition.
    #
Stefan Behnel's avatar
Stefan Behnel committed
3802
    #  name     EncodedString   Name of the class
William Stein's avatar
William Stein committed
3803 3804 3805 3806
    #  doc      string or None
    #  body     StatNode        Attribute definition code
    #  entry    Symtab.Entry
    #  scope    PyClassScope
3807
    #  decorators    [DecoratorNode]        list of decorators or None
William Stein's avatar
William Stein committed
3808 3809 3810
    #
    #  The following subnodes are constructed internally:
    #
3811
    #  dict     DictNode   Class dictionary or Py3 namespace
William Stein's avatar
William Stein committed
3812 3813
    #  classobj ClassNode  Class object
    #  target   NameNode   Variable to assign class object to
3814

3815
    child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result",
3816
                   "target", "class_cell", "decorators"]
3817
    decorators = None
3818
    class_result = None
Stefan Behnel's avatar
Stefan Behnel committed
3819
    py3_style_class = False # Python3 style class (bases+kwargs)
3820

3821 3822
    def __init__(self, pos, name, bases, doc, body, decorators = None,
                 keyword_args = None, starstar_arg = None):
William Stein's avatar
William Stein committed
3823 3824 3825 3826
        StatNode.__init__(self, pos)
        self.name = name
        self.doc = doc
        self.body = body
3827
        self.decorators = decorators
William Stein's avatar
William Stein committed
3828
        import ExprNodes
3829
        if self.doc and Options.docstrings:
3830
            doc = embed_position(self.pos, self.doc)
3831
            doc_node = ExprNodes.StringNode(pos, value = doc)
William Stein's avatar
William Stein committed
3832 3833
        else:
            doc_node = None
3834 3835
        if keyword_args or starstar_arg:
            self.py3_style_class = True
3836
            self.bases = bases
3837
            self.metaclass = None
3838 3839 3840 3841 3842 3843 3844 3845 3846 3847
            if keyword_args and not starstar_arg:
                for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
                    if item.key.value == 'metaclass':
                        if self.metaclass is not None:
                            error(item.pos, "keyword argument 'metaclass' passed multiple times")
                        # special case: we already know the metaclass,
                        # so we don't need to do the "build kwargs,
                        # find metaclass" dance at runtime
                        self.metaclass = item.value
                        del keyword_args.key_value_pairs[i]
3848
            if starstar_arg:
3849
                self.mkw = ExprNodes.KeywordArgsNode(
3850 3851 3852 3853
                    pos, keyword_args = keyword_args and keyword_args.key_value_pairs or [],
                    starstar_arg = starstar_arg)
            elif keyword_args and keyword_args.key_value_pairs:
                self.mkw = keyword_args
3854 3855 3856
            else:
                self.mkw = ExprNodes.NullNode(pos)
            if self.metaclass is None:
3857 3858
                self.metaclass = ExprNodes.PyClassMetaclassNode(
                    pos, mkw = self.mkw, bases = self.bases)
3859 3860
            self.dict = ExprNodes.PyClassNamespaceNode(pos, name = name,
                        doc = doc_node, metaclass = self.metaclass, bases = self.bases,
3861
                        mkw = self.mkw)
3862 3863 3864 3865 3866 3867 3868 3869 3870 3871
            self.classobj = ExprNodes.Py3ClassNode(pos, name = name,
                    bases = self.bases, dict = self.dict, doc = doc_node,
                    metaclass = self.metaclass, mkw = self.mkw)
        else:
            self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
            self.metaclass = None
            self.mkw = None
            self.bases = None
            self.classobj = ExprNodes.ClassNode(pos, name = name,
                    bases = bases, dict = self.dict, doc = doc_node)
William Stein's avatar
William Stein committed
3872
        self.target = ExprNodes.NameNode(pos, name = name)
3873
        self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos)
3874

3875 3876
    def as_cclass(self):
        """
3877
        Return this node as if it were declared as an extension class
3878
        """
3879 3880 3881
        if self.py3_style_class:
            error(self.classobj.pos, "Python3 style class could not be represented as C class")
            return
3882 3883 3884 3885 3886 3887 3888
        bases = self.classobj.bases.args
        if len(bases) == 0:
            base_class_name = None
            base_class_module = None
        elif len(bases) == 1:
            base = bases[0]
            path = []
3889 3890
            from ExprNodes import AttributeNode, NameNode
            while isinstance(base, AttributeNode):
3891 3892
                path.insert(0, base.attribute)
                base = base.obj
3893
            if isinstance(base, NameNode):
3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
                path.insert(0, base.name)
                base_class_name = path[-1]
                if len(path) > 1:
                    base_class_module = u'.'.join(path[:-1])
                else:
                    base_class_module = None
            else:
                error(self.classobj.bases.args.pos, "Invalid base class")
        else:
            error(self.classobj.bases.args.pos, "C class may only have one base class")
            return None
3905 3906

        return CClassDefNode(self.pos,
3907 3908 3909 3910 3911
                             visibility = 'private',
                             module_name = None,
                             class_name = self.name,
                             base_class_module = base_class_module,
                             base_class_name = base_class_name,
3912
                             decorators = self.decorators,
3913 3914 3915
                             body = self.body,
                             in_pxd = False,
                             doc = self.doc)
3916

3917 3918
    def create_scope(self, env):
        genv = env
3919 3920
        while genv.is_py_class_scope or genv.is_c_class_scope:
            genv = genv.outer_scope
3921 3922
        cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
        return cenv
3923

William Stein's avatar
William Stein committed
3924
    def analyse_declarations(self, env):
3925 3926 3927 3928 3929 3930 3931 3932
        class_result = self.classobj
        if self.decorators:
            from ExprNodes import SimpleCallNode
            for decorator in self.decorators[::-1]:
                class_result = SimpleCallNode(
                    decorator.pos,
                    function = decorator.decorator,
                    args = [class_result])
3933
            self.decorators = None
3934 3935
        self.class_result = class_result
        self.class_result.analyse_declarations(env)
William Stein's avatar
William Stein committed
3936
        self.target.analyse_target_declaration(env)
3937
        cenv = self.create_scope(env)
3938
        cenv.directives = env.directives
3939 3940
        cenv.class_obj_cname = self.target.entry.cname
        self.body.analyse_declarations(cenv)
3941

William Stein's avatar
William Stein committed
3942
    def analyse_expressions(self, env):
3943 3944 3945 3946
        if self.py3_style_class:
            self.bases.analyse_expressions(env)
            self.metaclass.analyse_expressions(env)
            self.mkw.analyse_expressions(env)
William Stein's avatar
William Stein committed
3947
        self.dict.analyse_expressions(env)
3948
        self.class_result.analyse_expressions(env)
William Stein's avatar
William Stein committed
3949
        genv = env.global_scope()
3950
        cenv = self.scope
William Stein's avatar
William Stein committed
3951
        self.body.analyse_expressions(cenv)
3952
        self.target.analyse_target_expression(env, self.classobj)
3953
        self.class_cell.analyse_expressions(cenv)
3954

3955
    def generate_function_definitions(self, env, code):
3956
        self.generate_lambda_definitions(self.scope, code)
3957
        self.body.generate_function_definitions(self.scope, code)
3958

William Stein's avatar
William Stein committed
3959
    def generate_execution_code(self, code):
3960 3961
        code.pyclass_stack.append(self)
        cenv = self.scope
3962 3963 3964 3965
        if self.py3_style_class:
            self.bases.generate_evaluation_code(code)
            self.mkw.generate_evaluation_code(code)
            self.metaclass.generate_evaluation_code(code)
William Stein's avatar
William Stein committed
3966
        self.dict.generate_evaluation_code(code)
Vitja Makarov's avatar
Vitja Makarov committed
3967
        cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
3968
        self.class_cell.generate_evaluation_code(code)
Vitja Makarov's avatar
Vitja Makarov committed
3969
        self.body.generate_execution_code(code)
3970
        self.class_result.generate_evaluation_code(code)
3971 3972 3973
        self.class_cell.generate_injection_code(
            code, self.class_result.result())
        self.class_cell.generate_disposal_code(code)
3974
        cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
3975
        self.target.generate_assignment_code(self.class_result, code)
William Stein's avatar
William Stein committed
3976
        self.dict.generate_disposal_code(code)
3977
        self.dict.free_temps(code)
3978 3979 3980 3981 3982 3983 3984
        if self.py3_style_class:
            self.mkw.generate_disposal_code(code)
            self.mkw.free_temps(code)
            self.metaclass.generate_disposal_code(code)
            self.metaclass.free_temps(code)
            self.bases.generate_disposal_code(code)
            self.bases.free_temps(code)
3985
        code.pyclass_stack.pop()
William Stein's avatar
William Stein committed
3986

Robert Bradshaw's avatar
Robert Bradshaw committed
3987
class CClassDefNode(ClassDefNode):
William Stein's avatar
William Stein committed
3988 3989 3990 3991
    #  An extension type definition.
    #
    #  visibility         'private' or 'public' or 'extern'
    #  typedef_flag       boolean
Stefan Behnel's avatar
Stefan Behnel committed
3992
    #  api                boolean
William Stein's avatar
William Stein committed
3993 3994 3995 3996 3997 3998 3999 4000
    #  module_name        string or None    For import of extern type objects
    #  class_name         string            Unqualified name of class
    #  as_name            string or None    Name to declare as in this scope
    #  base_class_module  string or None    Module containing the base class
    #  base_class_name    string or None    Name of the base class
    #  objstruct_name     string or None    Specified C name of object struct
    #  typeobj_name       string or None    Specified C name of type object
    #  in_pxd             boolean           Is in a .pxd file
4001
    #  decorators         [DecoratorNode]   list of decorators or None
William Stein's avatar
William Stein committed
4002 4003 4004 4005
    #  doc                string or None
    #  body               StatNode or None
    #  entry              Symtab.Entry
    #  base_type          PyExtensionType or None
4006 4007
    #  buffer_defaults_node DictNode or None Declares defaults for a buffer
    #  buffer_defaults_pos
4008

4009
    child_attrs = ["body"]
4010 4011
    buffer_defaults_node = None
    buffer_defaults_pos = None
4012 4013 4014 4015
    typedef_flag = False
    api = False
    objstruct_name = None
    typeobj_name = None
4016
    decorators = None
4017
    shadow = False
4018

Robert Bradshaw's avatar
Robert Bradshaw committed
4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030
    def buffer_defaults(self, env):
        if not hasattr(self, '_buffer_defaults'):
            import Buffer
            if self.buffer_defaults_node:
                self._buffer_defaults = Buffer.analyse_buffer_options(
                    self.buffer_defaults_pos,
                    env, [], self.buffer_defaults_node,
                    need_complete=False)
            else:
                self._buffer_defaults = None
        return self._buffer_defaults

4031 4032 4033 4034 4035 4036 4037 4038
    def declare(self, env):
        if self.module_name and self.visibility != 'extern':
            module_path = self.module_name.split(".")
            home_scope = env.find_imported_module(module_path, self.pos)
            if not home_scope:
                return None
        else:
            home_scope = env
4039

4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051
        self.entry = home_scope.declare_c_class(
            name = self.class_name,
            pos = self.pos,
            defining = 0,
            implementing = 0,
            module_name = self.module_name,
            base_type = None,
            objstruct_cname = self.objstruct_name,
            typeobj_cname = self.typeobj_name,
            visibility = self.visibility,
            typedef_flag = self.typedef_flag,
            api = self.api,
Robert Bradshaw's avatar
Robert Bradshaw committed
4052
            buffer_defaults = self.buffer_defaults(env),
4053 4054
            shadow = self.shadow)

William Stein's avatar
William Stein committed
4055 4056 4057 4058
    def analyse_declarations(self, env):
        #print "CClassDefNode.analyse_declarations:", self.class_name
        #print "...visibility =", self.visibility
        #print "...module_name =", self.module_name
4059

William Stein's avatar
William Stein committed
4060 4061 4062
        if env.in_cinclude and not self.objstruct_name:
            error(self.pos, "Object struct name specification required for "
                "C class defined in 'extern from' block")
4063 4064 4065
        if self.decorators:
            error(self.pos,
                  "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name)
William Stein's avatar
William Stein committed
4066
        self.base_type = None
4067 4068
        # Now that module imports are cached, we need to
        # import the modules for extern classes.
4069 4070 4071 4072 4073 4074 4075
        if self.module_name:
            self.module = None
            for module in env.cimported_modules:
                if module.name == self.module_name:
                    self.module = module
            if self.module is None:
                self.module = ModuleScope(self.module_name, None, env.context)
4076
                self.module.has_extern_class = 1
Robert Bradshaw's avatar
Robert Bradshaw committed
4077
                env.add_imported_module(self.module)
4078

William Stein's avatar
William Stein committed
4079 4080 4081 4082 4083
        if self.base_class_name:
            if self.base_class_module:
                base_class_scope = env.find_module(self.base_class_module, self.pos)
            else:
                base_class_scope = env
4084 4085 4086 4087 4088 4089
            if self.base_class_name == 'object':
                # extension classes are special and don't need to inherit from object
                if base_class_scope is None or base_class_scope.lookup('object') is None:
                    self.base_class_name = None
                    self.base_class_module = None
                    base_class_scope = None
William Stein's avatar
William Stein committed
4090 4091 4092 4093 4094
            if base_class_scope:
                base_class_entry = base_class_scope.find(self.base_class_name, self.pos)
                if base_class_entry:
                    if not base_class_entry.is_type:
                        error(self.pos, "'%s' is not a type name" % self.base_class_name)
4095 4096 4097
                    elif not base_class_entry.type.is_extension_type and \
                             not (base_class_entry.type.is_builtin_type and \
                                  base_class_entry.type.objstruct_cname):
William Stein's avatar
William Stein committed
4098 4099
                        error(self.pos, "'%s' is not an extension type" % self.base_class_name)
                    elif not base_class_entry.type.is_complete():
4100 4101 4102
                        error(self.pos, "Base class '%s' of type '%s' is incomplete" % (
                            self.base_class_name, self.class_name))
                    elif base_class_entry.type.scope and base_class_entry.type.scope.directives and \
4103
                             base_class_entry.type.is_final_type:
4104 4105
                        error(self.pos, "Base class '%s' of type '%s' is final" % (
                            self.base_class_name, self.class_name))
4106 4107 4108 4109
                    elif base_class_entry.type.is_builtin_type and \
                             base_class_entry.type.name in ('tuple', 'str', 'bytes'):
                        error(self.pos, "inheritance from PyVarObject types like '%s' is not currently supported"
                              % base_class_entry.type.name)
William Stein's avatar
William Stein committed
4110 4111 4112
                    else:
                        self.base_type = base_class_entry.type
        has_body = self.body is not None
4113
        if self.module_name and self.visibility != 'extern':
4114 4115 4116 4117 4118 4119
            module_path = self.module_name.split(".")
            home_scope = env.find_imported_module(module_path, self.pos)
            if not home_scope:
                return
        else:
            home_scope = env
4120 4121

        if self.visibility == 'extern':
4122 4123 4124
            if (self.module_name == '__builtin__' and
                self.class_name in Builtin.builtin_types and
                env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython
4125
                warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1)
4126

4127
        self.entry = home_scope.declare_c_class(
4128
            name = self.class_name,
William Stein's avatar
William Stein committed
4129 4130 4131 4132 4133 4134 4135 4136
            pos = self.pos,
            defining = has_body and self.in_pxd,
            implementing = has_body and not self.in_pxd,
            module_name = self.module_name,
            base_type = self.base_type,
            objstruct_cname = self.objstruct_name,
            typeobj_cname = self.typeobj_name,
            visibility = self.visibility,
Stefan Behnel's avatar
Stefan Behnel committed
4137
            typedef_flag = self.typedef_flag,
4138
            api = self.api,
Robert Bradshaw's avatar
Robert Bradshaw committed
4139
            buffer_defaults = self.buffer_defaults(env),
4140
            shadow = self.shadow)
4141

4142 4143
        if self.shadow:
            home_scope.lookup(self.class_name).as_variable = self.entry
4144
        if home_scope is not env and self.visibility == 'extern':
4145
            env.add_imported_entry(self.class_name, self.entry, self.pos)
4146
        self.scope = scope = self.entry.type.scope
4147 4148
        if scope is not None:
            scope.directives = env.directives
4149

4150
        if self.doc and Options.docstrings:
4151
            scope.doc = embed_position(self.pos, self.doc)
4152

William Stein's avatar
William Stein committed
4153 4154 4155 4156 4157 4158 4159
        if has_body:
            self.body.analyse_declarations(scope)
            if self.in_pxd:
                scope.defined = 1
            else:
                scope.implemented = 1
        env.allocate_vtable_names(self.entry)
4160

William Stein's avatar
William Stein committed
4161 4162
    def analyse_expressions(self, env):
        if self.body:
Robert Bradshaw's avatar
Robert Bradshaw committed
4163 4164
            scope = self.entry.type.scope
            self.body.analyse_expressions(scope)
4165

4166
    def generate_function_definitions(self, env, code):
William Stein's avatar
William Stein committed
4167
        if self.body:
4168 4169
            self.generate_lambda_definitions(self.scope, code)
            self.body.generate_function_definitions(self.scope, code)
4170

William Stein's avatar
William Stein committed
4171 4172 4173 4174 4175
    def generate_execution_code(self, code):
        # This is needed to generate evaluation code for
        # default values of method arguments.
        if self.body:
            self.body.generate_execution_code(code)
4176

4177 4178 4179
    def annotate(self, code):
        if self.body:
            self.body.annotate(code)
William Stein's avatar
William Stein committed
4180 4181 4182 4183 4184 4185


class PropertyNode(StatNode):
    #  Definition of a property in an extension type.
    #
    #  name   string
4186
    #  doc    EncodedString or None    Doc string
William Stein's avatar
William Stein committed
4187
    #  body   StatListNode
4188

4189 4190
    child_attrs = ["body"]

William Stein's avatar
William Stein committed
4191 4192 4193
    def analyse_declarations(self, env):
        entry = env.declare_property(self.name, self.doc, self.pos)
        if entry:
4194
            entry.scope.directives = env.directives
William Stein's avatar
William Stein committed
4195
            self.body.analyse_declarations(entry.scope)
4196

William Stein's avatar
William Stein committed
4197 4198
    def analyse_expressions(self, env):
        self.body.analyse_expressions(env)
4199

4200 4201
    def generate_function_definitions(self, env, code):
        self.body.generate_function_definitions(env, code)
William Stein's avatar
William Stein committed
4202 4203 4204 4205

    def generate_execution_code(self, code):
        pass

4206 4207 4208
    def annotate(self, code):
        self.body.annotate(code)

William Stein's avatar
William Stein committed
4209 4210 4211 4212 4213

class GlobalNode(StatNode):
    # Global variable declaration.
    #
    # names    [string]
4214

4215 4216
    child_attrs = []

William Stein's avatar
William Stein committed
4217 4218 4219 4220 4221 4222
    def analyse_declarations(self, env):
        for name in self.names:
            env.declare_global(name, self.pos)

    def analyse_expressions(self, env):
        pass
4223

William Stein's avatar
William Stein committed
4224 4225 4226 4227
    def generate_execution_code(self, code):
        pass


4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245
class NonlocalNode(StatNode):
    # Nonlocal variable declaration via the 'nonlocal' keyword.
    #
    # names    [string]

    child_attrs = []

    def analyse_declarations(self, env):
        for name in self.names:
            env.declare_nonlocal(name, self.pos)

    def analyse_expressions(self, env):
        pass

    def generate_execution_code(self, code):
        pass


William Stein's avatar
William Stein committed
4246 4247 4248 4249
class ExprStatNode(StatNode):
    #  Expression used as a statement.
    #
    #  expr   ExprNode
4250 4251

    child_attrs = ["expr"]
4252

Robert Bradshaw's avatar
Robert Bradshaw committed
4253 4254 4255
    def analyse_declarations(self, env):
        import ExprNodes
        if isinstance(self.expr, ExprNodes.GeneralCallNode):
4256
            func = self.expr.function.as_cython_attribute()
Robert Bradshaw's avatar
Robert Bradshaw committed
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267
            if func == u'declare':
                args, kwds = self.expr.explicit_args_kwds()
                if len(args):
                    error(self.expr.pos, "Variable names must be specified.")
                for var, type_node in kwds.key_value_pairs:
                    type = type_node.analyse_as_type(env)
                    if type is None:
                        error(type_node.pos, "Unknown type")
                    else:
                        env.declare_var(var.value, type, var.pos, is_cdef = True)
                self.__class__ = PassStatNode
4268

William Stein's avatar
William Stein committed
4269
    def analyse_expressions(self, env):
4270
        self.expr.result_is_used = False # hint that .result() may safely be left empty
William Stein's avatar
William Stein committed
4271
        self.expr.analyse_expressions(env)
4272

4273
    def nogil_check(self, env):
4274
        if self.expr.type.is_pyobject and self.expr.is_temp:
4275 4276 4277 4278
            self.gil_error()

    gil_message = "Discarding owned Python object"

William Stein's avatar
William Stein committed
4279 4280
    def generate_execution_code(self, code):
        self.expr.generate_evaluation_code(code)
4281 4282
        if not self.expr.is_temp and self.expr.result():
            code.putln("%s;" % self.expr.result())
William Stein's avatar
William Stein committed
4283
        self.expr.generate_disposal_code(code)
4284
        self.expr.free_temps(code)
William Stein's avatar
William Stein committed
4285

4286 4287 4288
    def generate_function_definitions(self, env, code):
        self.expr.generate_function_definitions(env, code)

4289 4290 4291
    def annotate(self, code):
        self.expr.annotate(code)

William Stein's avatar
William Stein committed
4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302

class AssignmentNode(StatNode):
    #  Abstract base class for assignment nodes.
    #
    #  The analyse_expressions and generate_execution_code
    #  phases of assignments are split into two sub-phases
    #  each, to enable all the right hand sides of a
    #  parallel assignment to be evaluated before assigning
    #  to any of the left hand sides.

    def analyse_expressions(self, env):
4303 4304
        self.analyse_types(env)

4305 4306 4307
#       def analyse_expressions(self, env):
#           self.analyse_expressions_1(env)
#           self.analyse_expressions_2(env)
William Stein's avatar
William Stein committed
4308 4309 4310 4311

    def generate_execution_code(self, code):
        self.generate_rhs_evaluation_code(code)
        self.generate_assignment_code(code)
4312

William Stein's avatar
William Stein committed
4313 4314 4315 4316 4317 4318 4319 4320

class SingleAssignmentNode(AssignmentNode):
    #  The simplest case:
    #
    #    a = b
    #
    #  lhs      ExprNode      Left hand side
    #  rhs      ExprNode      Right hand side
4321
    #  first    bool          Is this guaranteed the first assignment to lhs?
4322

4323
    child_attrs = ["lhs", "rhs"]
4324
    first = False
4325
    declaration_only = False
William Stein's avatar
William Stein committed
4326 4327

    def analyse_declarations(self, env):
4328
        import ExprNodes
4329

4330 4331
        # handle declarations of the form x = cython.foo()
        if isinstance(self.rhs, ExprNodes.CallNode):
4332
            func_name = self.rhs.function.as_cython_attribute()
4333 4334
            if func_name:
                args, kwds = self.rhs.explicit_args_kwds()
4335

4336
                if func_name in ['declare', 'typedef']:
Robert Bradshaw's avatar
Robert Bradshaw committed
4337
                    if len(args) > 2 or kwds is not None:
4338
                        error(self.rhs.pos, "Can only declare one type at a time.")
4339
                        return
4340

4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
                    type = args[0].analyse_as_type(env)
                    if type is None:
                        error(args[0].pos, "Unknown type")
                        return
                    lhs = self.lhs
                    if func_name == 'declare':
                        if isinstance(lhs, ExprNodes.NameNode):
                            vars = [(lhs.name, lhs.pos)]
                        elif isinstance(lhs, ExprNodes.TupleNode):
                            vars = [(var.name, var.pos) for var in lhs.args]
                        else:
                            error(lhs.pos, "Invalid declaration")
                            return
                        for var, pos in vars:
                            env.declare_var(var, type, pos, is_cdef = True)
Robert Bradshaw's avatar
Robert Bradshaw committed
4356 4357 4358 4359 4360
                        if len(args) == 2:
                            # we have a value
                            self.rhs = args[1]
                        else:
                            self.declaration_only = True
4361
                    else:
Robert Bradshaw's avatar
Robert Bradshaw committed
4362
                        self.declaration_only = True
4363 4364
                        if not isinstance(lhs, ExprNodes.NameNode):
                            error(lhs.pos, "Invalid declaration.")
4365
                        env.declare_typedef(lhs.name, type, self.pos, visibility='private')
4366

4367 4368 4369
                elif func_name in ['struct', 'union']:
                    self.declaration_only = True
                    if len(args) > 0 or kwds is None:
4370
                        error(self.rhs.pos, "Struct or union members must be given by name.")
4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387
                        return
                    members = []
                    for member, type_node in kwds.key_value_pairs:
                        type = type_node.analyse_as_type(env)
                        if type is None:
                            error(type_node.pos, "Unknown type")
                        else:
                            members.append((member.value, type, member.pos))
                    if len(members) < len(kwds.key_value_pairs):
                        return
                    if not isinstance(self.lhs, ExprNodes.NameNode):
                        error(self.lhs.pos, "Invalid declaration.")
                    name = self.lhs.name
                    scope = StructOrUnionScope(name)
                    env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
                    for member, type, pos in members:
                        scope.declare_var(member, type, pos)
4388

Mark Florisson's avatar
Mark Florisson committed
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399
                elif func_name == 'fused_type':
                    # dtype = cython.fused_type(...)
                    self.declaration_only = True
                    if kwds:
                        error(self.rhs.function.pos,
                              "fused_type does not take keyword arguments")

                    fusednode = FusedTypeNode(self.rhs.pos,
                                              name = self.lhs.name, types=args)
                    fusednode.analyse_declarations(env)

4400 4401 4402 4403
        if self.declaration_only:
            return
        else:
            self.lhs.analyse_target_declaration(env)
4404

4405
    def analyse_types(self, env, use_temp = 0):
4406 4407
        import ExprNodes

William Stein's avatar
William Stein committed
4408 4409
        self.rhs.analyse_types(env)
        self.lhs.analyse_target_types(env)
4410
        self.lhs.gil_assignment_check(env)
4411 4412 4413 4414 4415

        if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast:
            self.lhs.memslice_broadcast = True
            self.rhs.memslice_broadcast = True

4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427
        is_index_node = isinstance(self.lhs, ExprNodes.IndexNode)
        if (is_index_node and not self.rhs.type.is_memoryviewslice and
            (self.lhs.memslice_slice or self.lhs.is_memslice_copy) and
            (self.lhs.type.dtype.assignable_from(self.rhs.type) or
             self.rhs.type.is_pyobject)):
            # scalar slice assignment
            self.lhs.is_memslice_scalar_assignment = True
            dtype = self.lhs.type.dtype
        else:
            dtype = self.lhs.type

        self.rhs = self.rhs.coerce_to(dtype, env)
William Stein's avatar
William Stein committed
4428 4429
        if use_temp:
            self.rhs = self.rhs.coerce_to_temp(env)
4430

William Stein's avatar
William Stein committed
4431 4432
    def generate_rhs_evaluation_code(self, code):
        self.rhs.generate_evaluation_code(code)
4433

William Stein's avatar
William Stein committed
4434 4435 4436
    def generate_assignment_code(self, code):
        self.lhs.generate_assignment_code(self.rhs, code)

4437 4438 4439
    def generate_function_definitions(self, env, code):
        self.rhs.generate_function_definitions(env, code)

4440 4441 4442 4443
    def annotate(self, code):
        self.lhs.annotate(code)
        self.rhs.annotate(code)

William Stein's avatar
William Stein committed
4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455

class CascadedAssignmentNode(AssignmentNode):
    #  An assignment with multiple left hand sides:
    #
    #    a = b = c
    #
    #  lhs_list   [ExprNode]   Left hand sides
    #  rhs        ExprNode     Right hand sides
    #
    #  Used internally:
    #
    #  coerced_rhs_list   [ExprNode]   RHS coerced to type of each LHS
4456

4457
    child_attrs = ["lhs_list", "rhs", "coerced_rhs_list"]
4458
    coerced_rhs_list = None
4459

William Stein's avatar
William Stein committed
4460 4461 4462
    def analyse_declarations(self, env):
        for lhs in self.lhs_list:
            lhs.analyse_target_declaration(env)
4463

4464
    def analyse_types(self, env, use_temp = 0):
4465 4466
        from ExprNodes import CloneNode, ProxyNode

William Stein's avatar
William Stein committed
4467
        self.rhs.analyse_types(env)
Stefan Behnel's avatar
Stefan Behnel committed
4468 4469 4470 4471 4472
        if not self.rhs.is_simple():
            if use_temp:
                self.rhs = self.rhs.coerce_to_temp(env)
            else:
                self.rhs = self.rhs.coerce_to_simple(env)
4473 4474

        self.rhs = ProxyNode(self.rhs)
William Stein's avatar
William Stein committed
4475 4476 4477
        self.coerced_rhs_list = []
        for lhs in self.lhs_list:
            lhs.analyse_target_types(env)
4478
            lhs.gil_assignment_check(env)
William Stein's avatar
William Stein committed
4479 4480 4481
            rhs = CloneNode(self.rhs)
            rhs = rhs.coerce_to(lhs.type, env)
            self.coerced_rhs_list.append(rhs)
4482

William Stein's avatar
William Stein committed
4483 4484
    def generate_rhs_evaluation_code(self, code):
        self.rhs.generate_evaluation_code(code)
4485

William Stein's avatar
William Stein committed
4486 4487 4488 4489 4490 4491 4492 4493
    def generate_assignment_code(self, code):
        for i in range(len(self.lhs_list)):
            lhs = self.lhs_list[i]
            rhs = self.coerced_rhs_list[i]
            rhs.generate_evaluation_code(code)
            lhs.generate_assignment_code(rhs, code)
            # Assignment has disposed of the cloned RHS
        self.rhs.generate_disposal_code(code)
4494
        self.rhs.free_temps(code)
William Stein's avatar
William Stein committed
4495

4496 4497 4498
    def generate_function_definitions(self, env, code):
        self.rhs.generate_function_definitions(env, code)

4499 4500 4501 4502 4503
    def annotate(self, code):
        for i in range(len(self.lhs_list)):
            lhs = self.lhs_list[i].annotate(code)
            rhs = self.coerced_rhs_list[i].annotate(code)
        self.rhs.annotate(code)
4504

4505

William Stein's avatar
William Stein committed
4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518
class ParallelAssignmentNode(AssignmentNode):
    #  A combined packing/unpacking assignment:
    #
    #    a, b, c =  d, e, f
    #
    #  This has been rearranged by the parser into
    #
    #    a = d ; b = e ; c = f
    #
    #  but we must evaluate all the right hand sides
    #  before assigning to any of the left hand sides.
    #
    #  stats     [AssignmentNode]   The constituent assignments
4519

4520 4521
    child_attrs = ["stats"]

William Stein's avatar
William Stein committed
4522 4523 4524
    def analyse_declarations(self, env):
        for stat in self.stats:
            stat.analyse_declarations(env)
4525

William Stein's avatar
William Stein committed
4526 4527
    def analyse_expressions(self, env):
        for stat in self.stats:
4528 4529
            stat.analyse_types(env, use_temp = 1)

Robert Bradshaw's avatar
Robert Bradshaw committed
4530 4531 4532 4533 4534
#    def analyse_expressions(self, env):
#        for stat in self.stats:
#            stat.analyse_expressions_1(env, use_temp = 1)
#        for stat in self.stats:
#            stat.analyse_expressions_2(env)
4535

William Stein's avatar
William Stein committed
4536 4537 4538 4539 4540 4541
    def generate_execution_code(self, code):
        for stat in self.stats:
            stat.generate_rhs_evaluation_code(code)
        for stat in self.stats:
            stat.generate_assignment_code(code)

4542 4543 4544 4545
    def generate_function_definitions(self, env, code):
        for stat in self.stats:
            stat.generate_function_definitions(env, code)

4546 4547 4548 4549 4550
    def annotate(self, code):
        for stat in self.stats:
            stat.annotate(code)


4551
class InPlaceAssignmentNode(AssignmentNode):
Craig Citro's avatar
Craig Citro committed
4552
    #  An in place arithmetic operand:
4553 4554 4555 4556 4557 4558 4559
    #
    #    a += b
    #    a -= b
    #    ...
    #
    #  lhs      ExprNode      Left hand side
    #  rhs      ExprNode      Right hand side
Stefan Behnel's avatar
Stefan Behnel committed
4560
    #  operator char          one of "+-*/%^&|"
4561
    #
4562 4563 4564 4565 4566 4567 4568
    #  This code is a bit tricky because in order to obey Python
    #  semantics the sub-expressions (e.g. indices) of the lhs must
    #  not be evaluated twice. So we must re-use the values calculated
    #  in evaluation phase for the assignment phase as well.
    #  Fortunately, the type of the lhs node is fairly constrained
    #  (it must be a NameNode, AttributeNode, or IndexNode).

4569
    child_attrs = ["lhs", "rhs"]
4570

4571 4572
    def analyse_declarations(self, env):
        self.lhs.analyse_target_declaration(env)
4573

4574
    def analyse_types(self, env):
4575 4576
        import ExprNodes

4577 4578
        self.rhs.analyse_types(env)
        self.lhs.analyse_target_types(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
4579

4580 4581 4582 4583 4584
        # When assigning to a fully indexed buffer or memoryview, coerce the rhs
        if (isinstance(self.lhs, ExprNodes.IndexNode) and
                (self.lhs.memslice_index or self.lhs.is_buffer_access)):
            self.rhs = self.rhs.coerce_to(self.lhs.type, env)

4585
    def generate_execution_code(self, code):
4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596
        import ExprNodes
        self.rhs.generate_evaluation_code(code)
        self.lhs.generate_subexpr_evaluation_code(code)
        c_op = self.operator
        if c_op == "//":
            c_op = "/"
        elif c_op == "**":
            error(self.pos, "No C inplace power operator")
        if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
            if self.lhs.type.is_pyobject:
                error(self.pos, "In-place operators not allowed on object buffers in this release.")
4597 4598
            if (c_op in ('/', '%') and self.lhs.type.is_int
                and not code.globalstate.directives['cdivision']):
Robert Bradshaw's avatar
Robert Bradshaw committed
4599
                error(self.pos, "In-place non-c divide operators not allowed on int buffers.")
4600 4601 4602 4603 4604 4605 4606 4607 4608 4609
            self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
        else:
            # C++
            # TODO: make sure overload is declared
            code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()))
        self.lhs.generate_subexpr_disposal_code(code)
        self.lhs.free_subexpr_temps(code)
        self.rhs.generate_disposal_code(code)
        self.rhs.free_temps(code)

4610 4611 4612
    def annotate(self, code):
        self.lhs.annotate(code)
        self.rhs.annotate(code)
4613

4614 4615
    def create_binop_node(self):
        import ExprNodes
4616
        return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs)
4617

William Stein's avatar
William Stein committed
4618 4619 4620 4621

class PrintStatNode(StatNode):
    #  print statement
    #
4622
    #  arg_tuple         TupleNode
4623
    #  stream            ExprNode or None (stdout)
4624
    #  append_newline    boolean
4625

4626
    child_attrs = ["arg_tuple", "stream"]
4627

William Stein's avatar
William Stein committed
4628
    def analyse_expressions(self, env):
4629 4630 4631
        if self.stream:
            self.stream.analyse_expressions(env)
            self.stream = self.stream.coerce_to_pyobject(env)
4632
        self.arg_tuple.analyse_expressions(env)
4633
        self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
4634
        env.use_utility_code(printing_utility_code)
4635 4636
        if len(self.arg_tuple.args) == 1 and self.append_newline:
            env.use_utility_code(printing_one_utility_code)
4637

4638
    nogil_check = Node.gil_error
4639
    gil_message = "Python print statement"
4640

William Stein's avatar
William Stein committed
4641
    def generate_execution_code(self, code):
4642 4643 4644 4645 4646
        if self.stream:
            self.stream.generate_evaluation_code(code)
            stream_result = self.stream.py_result()
        else:
            stream_result = '0'
4647 4648 4649
        if len(self.arg_tuple.args) == 1 and self.append_newline:
            arg = self.arg_tuple.args[0]
            arg.generate_evaluation_code(code)
4650

4651
            code.putln(
4652 4653
                "if (__Pyx_PrintOne(%s, %s) < 0) %s" % (
                    stream_result,
4654 4655 4656 4657 4658 4659 4660
                    arg.py_result(),
                    code.error_goto(self.pos)))
            arg.generate_disposal_code(code)
            arg.free_temps(code)
        else:
            self.arg_tuple.generate_evaluation_code(code)
            code.putln(
4661 4662
                "if (__Pyx_Print(%s, %s, %d) < 0) %s" % (
                    stream_result,
4663 4664 4665 4666 4667
                    self.arg_tuple.py_result(),
                    self.append_newline,
                    code.error_goto(self.pos)))
            self.arg_tuple.generate_disposal_code(code)
            self.arg_tuple.free_temps(code)
4668

4669 4670 4671 4672
        if self.stream:
            self.stream.generate_disposal_code(code)
            self.stream.free_temps(code)

4673
    def generate_function_definitions(self, env, code):
4674 4675
        if self.stream:
            self.stream.generate_function_definitions(env, code)
4676
        self.arg_tuple.generate_function_definitions(env, code)
4677

4678
    def annotate(self, code):
4679 4680
        if self.stream:
            self.stream.annotate(code)
4681
        self.arg_tuple.annotate(code)
William Stein's avatar
William Stein committed
4682 4683


4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697
class ExecStatNode(StatNode):
    #  exec statement
    #
    #  args     [ExprNode]

    child_attrs = ["args"]

    def analyse_expressions(self, env):
        for i, arg in enumerate(self.args):
            arg.analyse_expressions(env)
            arg = arg.coerce_to_pyobject(env)
            self.args[i] = arg
        env.use_utility_code(Builtin.pyexec_utility_code)

4698
    nogil_check = Node.gil_error
4699 4700 4701 4702 4703 4704 4705 4706
    gil_message = "Python exec statement"

    def generate_execution_code(self, code):
        args = []
        for arg in self.args:
            arg.generate_evaluation_code(code)
            args.append( arg.py_result() )
        args = tuple(args + ['0', '0'][:3-len(args)])
4707
        temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
Stefan Behnel's avatar
Stefan Behnel committed
4708
        code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % (
4709
                (temp_result,) + args))
4710 4711
        for arg in self.args:
            arg.generate_disposal_code(code)
4712
            arg.free_temps(code)
4713
        code.putln(
4714 4715 4716 4717
            code.error_goto_if_null(temp_result, self.pos))
        code.put_gotref(temp_result)
        code.put_decref_clear(temp_result, py_object_type)
        code.funcstate.release_temp(temp_result)
4718 4719 4720 4721 4722 4723

    def annotate(self, code):
        for arg in self.args:
            arg.annotate(code)


William Stein's avatar
William Stein committed
4724 4725 4726 4727
class DelStatNode(StatNode):
    #  del statement
    #
    #  args     [ExprNode]
4728

4729 4730
    child_attrs = ["args"]

William Stein's avatar
William Stein committed
4731 4732 4733
    def analyse_declarations(self, env):
        for arg in self.args:
            arg.analyse_target_declaration(env)
4734

William Stein's avatar
William Stein committed
4735 4736
    def analyse_expressions(self, env):
        for arg in self.args:
4737
            arg.analyse_target_expression(env, None)
4738 4739
            if arg.type.is_pyobject or (arg.is_name and
                                        arg.type.is_memoryviewslice):
Robert Bradshaw's avatar
Robert Bradshaw committed
4740
                pass
Robert Bradshaw's avatar
Robert Bradshaw committed
4741
            elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
Robert Bradshaw's avatar
Robert Bradshaw committed
4742
                self.cpp_check(env)
4743
            elif arg.type.is_cpp_class:
Robert Bradshaw's avatar
merge  
Robert Bradshaw committed
4744
                error(arg.pos, "Deletion of non-heap C++ object")
4745
            else:
Robert Bradshaw's avatar
Robert Bradshaw committed
4746
                error(arg.pos, "Deletion of non-Python, non-C++ object")
4747
            #arg.release_target_temp(env)
4748

4749
    def nogil_check(self, env):
4750 4751
        for arg in self.args:
            if arg.type.is_pyobject:
4752
                self.gil_error()
4753

4754 4755
    gil_message = "Deleting Python object"

William Stein's avatar
William Stein committed
4756 4757
    def generate_execution_code(self, code):
        for arg in self.args:
4758
            if arg.type.is_pyobject or arg.type.is_memoryviewslice:
William Stein's avatar
William Stein committed
4759
                arg.generate_deletion_code(code)
4760
            elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
Robert Bradshaw's avatar
Robert Bradshaw committed
4761
                arg.generate_result_code(code)
Robert Bradshaw's avatar
merge  
Robert Bradshaw committed
4762
                code.putln("delete %s;" % arg.result())
William Stein's avatar
William Stein committed
4763 4764
            # else error reported earlier

4765 4766 4767 4768
    def annotate(self, code):
        for arg in self.args:
            arg.annotate(code)

William Stein's avatar
William Stein committed
4769 4770 4771

class PassStatNode(StatNode):
    #  pass statement
4772 4773

    child_attrs = []
4774

William Stein's avatar
William Stein committed
4775 4776
    def analyse_expressions(self, env):
        pass
4777

William Stein's avatar
William Stein committed
4778 4779 4780 4781
    def generate_execution_code(self, code):
        pass


4782 4783 4784 4785 4786 4787 4788 4789 4790
class IndirectionNode(StatListNode):
    """
    This adds an indirection so that the node can be shared and a subtree can
    be removed at any time by clearing self.stats.
    """

    def __init__(self, stats):
        super(IndirectionNode, self).__init__(stats[0].pos, stats=stats)

William Stein's avatar
William Stein committed
4791 4792
class BreakStatNode(StatNode):

4793
    child_attrs = []
4794
    is_terminator = True
4795

William Stein's avatar
William Stein committed
4796 4797
    def analyse_expressions(self, env):
        pass
4798

William Stein's avatar
William Stein committed
4799 4800 4801 4802
    def generate_execution_code(self, code):
        if not code.break_label:
            error(self.pos, "break statement not inside loop")
        else:
4803
            code.put_goto(code.break_label)
William Stein's avatar
William Stein committed
4804 4805 4806 4807


class ContinueStatNode(StatNode):

4808
    child_attrs = []
4809
    is_terminator = True
4810

William Stein's avatar
William Stein committed
4811 4812
    def analyse_expressions(self, env):
        pass
4813

William Stein's avatar
William Stein committed
4814
    def generate_execution_code(self, code):
4815
        if code.funcstate.in_try_finally:
William Stein's avatar
William Stein committed
4816 4817 4818 4819
            error(self.pos, "continue statement inside try of try...finally")
        elif not code.continue_label:
            error(self.pos, "continue statement not inside loop")
        else:
4820
            code.put_goto(code.continue_label)
William Stein's avatar
William Stein committed
4821 4822 4823 4824 4825 4826 4827


class ReturnStatNode(StatNode):
    #  return statement
    #
    #  value         ExprNode or None
    #  return_type   PyrexType
4828
    #  in_generator  return inside of generator => raise StopIteration
4829

4830
    child_attrs = ["value"]
4831
    is_terminator = True
4832
    in_generator = False
4833

4834 4835 4836
    # Whether we are in a parallel section
    in_parallel = False

William Stein's avatar
William Stein committed
4837 4838 4839 4840 4841 4842 4843 4844 4845
    def analyse_expressions(self, env):
        return_type = env.return_type
        self.return_type = return_type
        if not return_type:
            error(self.pos, "Return not inside a function body")
            return
        if self.value:
            self.value.analyse_types(env)
            if return_type.is_void or return_type.is_returncode:
4846
                error(self.value.pos,
William Stein's avatar
William Stein committed
4847 4848 4849 4850 4851 4852 4853 4854
                    "Return with value in void function")
            else:
                self.value = self.value.coerce_to(env.return_type, env)
        else:
            if (not return_type.is_void
                and not return_type.is_pyobject
                and not return_type.is_returncode):
                    error(self.pos, "Return value required")
4855

4856
    def nogil_check(self, env):
4857
        if self.return_type.is_pyobject:
4858
            self.gil_error()
4859 4860 4861

    gil_message = "Returning Python object"

William Stein's avatar
William Stein committed
4862
    def generate_execution_code(self, code):
4863
        code.mark_pos(self.pos)
William Stein's avatar
William Stein committed
4864 4865 4866
        if not self.return_type:
            # error reported earlier
            return
4867 4868 4869
        if self.return_type.is_pyobject:
            code.put_xdecref(Naming.retval_cname,
                             self.return_type)
4870

William Stein's avatar
William Stein committed
4871 4872
        if self.value:
            self.value.generate_evaluation_code(code)
4873 4874
            if self.return_type.is_memoryviewslice:
                import MemoryView
4875 4876 4877 4878 4879
                MemoryView.put_acquire_memoryviewslice(
                        lhs_cname=Naming.retval_cname,
                        lhs_type=self.return_type,
                        lhs_pos=self.value.pos,
                        rhs=self.value,
4880 4881
                        code=code,
                        have_gil=self.in_nogil_context)
4882 4883 4884 4885 4886 4887 4888
            elif self.in_generator:
                # return value == raise StopIteration(value), but uncatchable
                code.putln(
                    "%s = NULL; PyErr_SetObject(PyExc_StopIteration, %s);" % (
                        Naming.retval_cname,
                        self.value.result_as(self.return_type)))
                self.value.generate_disposal_code(code)
4889 4890 4891 4892 4893 4894
            else:
                self.value.make_owned_reference(code)
                code.putln(
                    "%s = %s;" % (
                        Naming.retval_cname,
                        self.value.result_as(self.return_type)))
4895
            self.value.generate_post_assignment_code(code)
4896
            self.value.free_temps(code)
William Stein's avatar
William Stein committed
4897 4898 4899 4900
        else:
            if self.return_type.is_pyobject:
                code.put_init_to_py_none(Naming.retval_cname, self.return_type)
            elif self.return_type.is_returncode:
4901 4902
                self.put_return(code, self.return_type.default_value)

4903
        for cname, type in code.funcstate.temps_holding_reference():
4904
            code.put_decref_clear(cname, type)
4905

4906
        code.put_goto(code.return_label)
4907

4908 4909 4910 4911 4912
    def put_return(self, code, value):
        if self.in_parallel:
            code.putln_openmp("#pragma omp critical(__pyx_returning)")
        code.putln("%s = %s;" % (Naming.retval_cname, value))

4913 4914 4915
    def generate_function_definitions(self, env, code):
        if self.value is not None:
            self.value.generate_function_definitions(env, code)
4916

4917 4918 4919
    def annotate(self, code):
        if self.value:
            self.value.annotate(code)
William Stein's avatar
William Stein committed
4920 4921 4922 4923 4924 4925 4926 4927


class RaiseStatNode(StatNode):
    #  raise statement
    #
    #  exc_type    ExprNode or None
    #  exc_value   ExprNode or None
    #  exc_tb      ExprNode or None
Haoyu Bai's avatar
Haoyu Bai committed
4928
    #  cause       ExprNode or None
4929

Haoyu Bai's avatar
Haoyu Bai committed
4930
    child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"]
4931
    is_terminator = True
4932

William Stein's avatar
William Stein committed
4933 4934 4935 4936 4937 4938 4939 4940 4941 4942
    def analyse_expressions(self, env):
        if self.exc_type:
            self.exc_type.analyse_types(env)
            self.exc_type = self.exc_type.coerce_to_pyobject(env)
        if self.exc_value:
            self.exc_value.analyse_types(env)
            self.exc_value = self.exc_value.coerce_to_pyobject(env)
        if self.exc_tb:
            self.exc_tb.analyse_types(env)
            self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
Haoyu Bai's avatar
Haoyu Bai committed
4943 4944 4945
        if self.cause:
            self.cause.analyse_types(env)
            self.cause = self.cause.coerce_to_pyobject(env)
4946 4947 4948 4949 4950
        # special cases for builtin exceptions
        self.builtin_exc_name = None
        if self.exc_type and not self.exc_value and not self.exc_tb:
            exc = self.exc_type
            import ExprNodes
Robert Bradshaw's avatar
Robert Bradshaw committed
4951 4952
            if (isinstance(exc, ExprNodes.SimpleCallNode) and
                not (exc.args or (exc.arg_tuple is not None and
4953
                                  exc.arg_tuple.args))):
4954 4955 4956 4957 4958
                exc = exc.function # extract the exception type
            if exc.is_name and exc.entry.is_builtin:
                self.builtin_exc_name = exc.name
                if self.builtin_exc_name == 'MemoryError':
                    self.exc_type = None # has a separate implementation
4959

4960
    nogil_check = Node.gil_error
4961 4962
    gil_message = "Raising exception"

William Stein's avatar
William Stein committed
4963
    def generate_execution_code(self, code):
4964 4965 4966 4967
        if self.builtin_exc_name == 'MemoryError':
            code.putln('PyErr_NoMemory(); %s' % code.error_goto(self.pos))
            return

William Stein's avatar
William Stein committed
4968 4969 4970 4971
        if self.exc_type:
            self.exc_type.generate_evaluation_code(code)
            type_code = self.exc_type.py_result()
        else:
Stefan Behnel's avatar
Stefan Behnel committed
4972
            type_code = "0"
William Stein's avatar
William Stein committed
4973 4974 4975 4976 4977 4978 4979 4980 4981 4982
        if self.exc_value:
            self.exc_value.generate_evaluation_code(code)
            value_code = self.exc_value.py_result()
        else:
            value_code = "0"
        if self.exc_tb:
            self.exc_tb.generate_evaluation_code(code)
            tb_code = self.exc_tb.py_result()
        else:
            tb_code = "0"
Haoyu Bai's avatar
Haoyu Bai committed
4983 4984 4985 4986 4987
        if self.cause:
            self.cause.generate_evaluation_code(code)
            cause_code = self.cause.py_result()
        else:
            cause_code = "0"
4988
        code.globalstate.use_utility_code(raise_utility_code)
4989
        code.putln(
Haoyu Bai's avatar
Haoyu Bai committed
4990
            "__Pyx_Raise(%s, %s, %s, %s);" % (
4991 4992
                type_code,
                value_code,
Haoyu Bai's avatar
Haoyu Bai committed
4993 4994 4995
                tb_code,
                cause_code))
        for obj in (self.exc_type, self.exc_value, self.exc_tb, self.cause):
4996 4997 4998
            if obj:
                obj.generate_disposal_code(code)
                obj.free_temps(code)
William Stein's avatar
William Stein committed
4999 5000 5001
        code.putln(
            code.error_goto(self.pos))

5002 5003 5004 5005 5006 5007 5008
    def generate_function_definitions(self, env, code):
        if self.exc_type is not None:
            self.exc_type.generate_function_definitions(env, code)
        if self.exc_value is not None:
            self.exc_value.generate_function_definitions(env, code)
        if self.exc_tb is not None:
            self.exc_tb.generate_function_definitions(env, code)
Haoyu Bai's avatar
Haoyu Bai committed
5009 5010
        if self.cause is not None:
            self.cause.generate_function_definitions(env, code)
5011

5012 5013 5014 5015 5016 5017 5018
    def annotate(self, code):
        if self.exc_type:
            self.exc_type.annotate(code)
        if self.exc_value:
            self.exc_value.annotate(code)
        if self.exc_tb:
            self.exc_tb.annotate(code)
Haoyu Bai's avatar
Haoyu Bai committed
5019 5020
        if self.cause:
            self.cause.annotate(code)
5021

William Stein's avatar
William Stein committed
5022

5023 5024
class ReraiseStatNode(StatNode):

5025
    child_attrs = []
5026
    is_terminator = True
5027

5028
    def analyse_expressions(self, env):
5029
        pass
5030

5031
    nogil_check = Node.gil_error
5032 5033
    gil_message = "Raising exception"

5034
    def generate_execution_code(self, code):
5035
        vars = code.funcstate.exc_vars
5036
        if vars:
5037
            code.globalstate.use_utility_code(restore_exception_utility_code)
5038 5039 5040 5041 5042 5043
            for varname in vars:
                code.put_giveref(varname)
            code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
            for varname in vars:
                code.put("%s = 0; " % varname)
            code.putln()
5044 5045
            code.putln(code.error_goto(self.pos))
        else:
5046 5047 5048
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("ReRaiseException", "Exceptions.c"))
            code.putln("__Pyx_ReraiseException(); %s" % code.error_goto(self.pos))
5049

William Stein's avatar
William Stein committed
5050 5051 5052 5053 5054
class AssertStatNode(StatNode):
    #  assert statement
    #
    #  cond    ExprNode
    #  value   ExprNode or None
5055

5056 5057
    child_attrs = ["cond", "value"]

William Stein's avatar
William Stein committed
5058 5059 5060 5061 5062
    def analyse_expressions(self, env):
        self.cond = self.cond.analyse_boolean_expression(env)
        if self.value:
            self.value.analyse_types(env)
            self.value = self.value.coerce_to_pyobject(env)
5063

5064
    nogil_check = Node.gil_error
5065
    gil_message = "Raising exception"
5066

William Stein's avatar
William Stein committed
5067
    def generate_execution_code(self, code):
5068
        code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS")
William Stein's avatar
William Stein committed
5069 5070
        self.cond.generate_evaluation_code(code)
        code.putln(
Robert Bradshaw's avatar
Robert Bradshaw committed
5071
            "if (unlikely(!%s)) {" %
5072
                self.cond.result())
William Stein's avatar
William Stein committed
5073
        if self.value:
5074
            self.value.generate_evaluation_code(code)
William Stein's avatar
William Stein committed
5075 5076 5077
            code.putln(
                "PyErr_SetObject(PyExc_AssertionError, %s);" %
                    self.value.py_result())
5078
            self.value.generate_disposal_code(code)
5079
            self.value.free_temps(code)
William Stein's avatar
William Stein committed
5080 5081 5082 5083 5084 5085 5086 5087
        else:
            code.putln(
                "PyErr_SetNone(PyExc_AssertionError);")
        code.putln(
                code.error_goto(self.pos))
        code.putln(
            "}")
        self.cond.generate_disposal_code(code)
5088
        self.cond.free_temps(code)
5089
        code.putln("#endif")
William Stein's avatar
William Stein committed
5090

5091 5092 5093 5094 5095
    def generate_function_definitions(self, env, code):
        self.cond.generate_function_definitions(env, code)
        if self.value is not None:
            self.value.generate_function_definitions(env, code)

5096 5097 5098 5099 5100 5101
    def annotate(self, code):
        self.cond.annotate(code)
        if self.value:
            self.value.annotate(code)


William Stein's avatar
William Stein committed
5102 5103 5104 5105 5106
class IfStatNode(StatNode):
    #  if statement
    #
    #  if_clauses   [IfClauseNode]
    #  else_clause  StatNode or None
5107 5108

    child_attrs = ["if_clauses", "else_clause"]
5109

William Stein's avatar
William Stein committed
5110 5111 5112 5113 5114
    def analyse_declarations(self, env):
        for if_clause in self.if_clauses:
            if_clause.analyse_declarations(env)
        if self.else_clause:
            self.else_clause.analyse_declarations(env)
5115

William Stein's avatar
William Stein committed
5116 5117 5118 5119 5120
    def analyse_expressions(self, env):
        for if_clause in self.if_clauses:
            if_clause.analyse_expressions(env)
        if self.else_clause:
            self.else_clause.analyse_expressions(env)
5121

William Stein's avatar
William Stein committed
5122
    def generate_execution_code(self, code):
5123
        code.mark_pos(self.pos)
5124 5125 5126 5127 5128
        end_label = code.new_label()
        for if_clause in self.if_clauses:
            if_clause.generate_execution_code(code, end_label)
        if self.else_clause:
            code.putln("/*else*/ {")
William Stein's avatar
William Stein committed
5129
            self.else_clause.generate_execution_code(code)
5130 5131
            code.putln("}")
        code.put_label(end_label)
5132

5133 5134 5135 5136 5137
    def generate_function_definitions(self, env, code):
        for clause in self.if_clauses:
            clause.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)
5138

5139 5140 5141 5142 5143
    def annotate(self, code):
        for if_clause in self.if_clauses:
            if_clause.annotate(code)
        if self.else_clause:
            self.else_clause.annotate(code)
William Stein's avatar
William Stein committed
5144 5145 5146 5147 5148 5149 5150


class IfClauseNode(Node):
    #  if or elif clause in an if statement
    #
    #  condition   ExprNode
    #  body        StatNode
5151

5152 5153
    child_attrs = ["condition", "body"]

William Stein's avatar
William Stein committed
5154 5155
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
5156

William Stein's avatar
William Stein committed
5157 5158 5159 5160
    def analyse_expressions(self, env):
        self.condition = \
            self.condition.analyse_temp_boolean_expression(env)
        self.body.analyse_expressions(env)
5161 5162 5163

    def get_constant_condition_result(self):
        if self.condition.has_constant_result():
5164
            return bool(self.condition.constant_result)
5165 5166 5167
        else:
            return None

William Stein's avatar
William Stein committed
5168 5169 5170 5171
    def generate_execution_code(self, code, end_label):
        self.condition.generate_evaluation_code(code)
        code.putln(
            "if (%s) {" %
5172
                self.condition.result())
5173 5174
        self.condition.generate_disposal_code(code)
        self.condition.free_temps(code)
William Stein's avatar
William Stein committed
5175
        self.body.generate_execution_code(code)
5176
        code.put_goto(end_label)
William Stein's avatar
William Stein committed
5177
        code.putln("}")
5178

5179 5180 5181 5182
    def generate_function_definitions(self, env, code):
        self.condition.generate_function_definitions(env, code)
        self.body.generate_function_definitions(env, code)

5183 5184 5185
    def annotate(self, code):
        self.condition.annotate(code)
        self.body.annotate(code)
5186

5187 5188 5189 5190 5191 5192

class SwitchCaseNode(StatNode):
    # Generated in the optimization of an if-elif-else node
    #
    # conditions    [ExprNode]
    # body          StatNode
5193

5194
    child_attrs = ['conditions', 'body']
5195

5196 5197
    def generate_execution_code(self, code):
        for cond in self.conditions:
5198
            code.mark_pos(cond.pos)
5199 5200
            cond.generate_evaluation_code(code)
            code.putln("case %s:" % cond.result())
5201 5202
        self.body.generate_execution_code(code)
        code.putln("break;")
5203 5204 5205 5206 5207

    def generate_function_definitions(self, env, code):
        for cond in self.conditions:
            cond.generate_function_definitions(env, code)
        self.body.generate_function_definitions(env, code)
5208

5209 5210 5211
    def annotate(self, code):
        for cond in self.conditions:
            cond.annotate(code)
5212
        self.body.annotate(code)
5213 5214 5215 5216 5217 5218 5219

class SwitchStatNode(StatNode):
    # Generated in the optimization of an if-elif-else node
    #
    # test          ExprNode
    # cases         [SwitchCaseNode]
    # else_clause   StatNode or None
5220

5221
    child_attrs = ['test', 'cases', 'else_clause']
5222

5223
    def generate_execution_code(self, code):
5224
        self.test.generate_evaluation_code(code)
5225
        code.putln("switch (%s) {" % self.test.result())
5226 5227 5228 5229 5230
        for case in self.cases:
            case.generate_execution_code(code)
        if self.else_clause is not None:
            code.putln("default:")
            self.else_clause.generate_execution_code(code)
5231
            code.putln("break;")
5232 5233
        code.putln("}")

5234 5235 5236 5237 5238 5239 5240
    def generate_function_definitions(self, env, code):
        self.test.generate_function_definitions(env, code)
        for case in self.cases:
            case.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)

5241 5242 5243 5244
    def annotate(self, code):
        self.test.annotate(code)
        for case in self.cases:
            case.annotate(code)
5245 5246
        if self.else_clause is not None:
            self.else_clause.annotate(code)
5247

5248
class LoopNode(object):
5249
    pass
5250

5251

5252
class WhileStatNode(LoopNode, StatNode):
William Stein's avatar
William Stein committed
5253 5254 5255 5256 5257
    #  while statement
    #
    #  condition    ExprNode
    #  body         StatNode
    #  else_clause  StatNode
5258 5259

    child_attrs = ["condition", "body", "else_clause"]
5260

William Stein's avatar
William Stein committed
5261 5262 5263 5264
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
        if self.else_clause:
            self.else_clause.analyse_declarations(env)
5265

William Stein's avatar
William Stein committed
5266
    def analyse_expressions(self, env):
5267 5268
        if self.condition:
            self.condition = self.condition.analyse_temp_boolean_expression(env)
William Stein's avatar
William Stein committed
5269 5270 5271
        self.body.analyse_expressions(env)
        if self.else_clause:
            self.else_clause.analyse_expressions(env)
5272

William Stein's avatar
William Stein committed
5273 5274 5275 5276
    def generate_execution_code(self, code):
        old_loop_labels = code.new_loop_labels()
        code.putln(
            "while (1) {")
5277 5278 5279 5280 5281 5282 5283
        if self.condition:
            self.condition.generate_evaluation_code(code)
            self.condition.generate_disposal_code(code)
            code.putln(
                "if (!%s) break;" %
                    self.condition.result())
            self.condition.free_temps(code)
William Stein's avatar
William Stein committed
5284
        self.body.generate_execution_code(code)
5285
        code.put_label(code.continue_label)
William Stein's avatar
William Stein committed
5286 5287 5288 5289 5290 5291 5292 5293 5294
        code.putln("}")
        break_label = code.break_label
        code.set_loop_labels(old_loop_labels)
        if self.else_clause:
            code.putln("/*else*/ {")
            self.else_clause.generate_execution_code(code)
            code.putln("}")
        code.put_label(break_label)

5295
    def generate_function_definitions(self, env, code):
5296 5297
        if self.condition:
            self.condition.generate_function_definitions(env, code)
5298 5299 5300 5301
        self.body.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)

5302
    def annotate(self, code):
5303 5304
        if self.condition:
            self.condition.annotate(code)
5305 5306 5307 5308
        self.body.annotate(code)
        if self.else_clause:
            self.else_clause.annotate(code)

William Stein's avatar
William Stein committed
5309

5310 5311 5312 5313
class DictIterationNextNode(Node):
    # Helper node for calling PyDict_Next() inside of a WhileStatNode
    # and checking the dictionary size for changes.  Created in
    # Optimize.py.
5314 5315 5316
    child_attrs = ['dict_obj', 'expected_size', 'pos_index_var',
                   'coerced_key_var', 'coerced_value_var', 'coerced_tuple_var',
                   'key_target', 'value_target', 'tuple_target', 'is_dict_flag']
5317

5318 5319 5320 5321 5322 5323
    coerced_key_var = key_ref = None
    coerced_value_var = value_ref = None
    coerced_tuple_var = tuple_ref = None

    def __init__(self, dict_obj, expected_size, pos_index_var,
                 key_target, value_target, tuple_target, is_dict_flag):
5324 5325 5326 5327
        Node.__init__(
            self, dict_obj.pos,
            dict_obj = dict_obj,
            expected_size = expected_size,
5328 5329 5330 5331 5332 5333
            pos_index_var = pos_index_var,
            key_target = key_target,
            value_target = value_target,
            tuple_target = tuple_target,
            is_dict_flag = is_dict_flag,
            is_temp = True,
5334 5335 5336
            type = PyrexTypes.c_bint_type)

    def analyse_expressions(self, env):
5337
        import ExprNodes
5338 5339
        self.dict_obj.analyse_types(env)
        self.expected_size.analyse_types(env)
5340 5341 5342
        if self.pos_index_var: self.pos_index_var.analyse_types(env)
        if self.key_target:
            self.key_target.analyse_target_types(env)
5343
            self.key_ref = ExprNodes.TempNode(self.key_target.pos, PyrexTypes.py_object_type)
5344 5345 5346
            self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env)
        if self.value_target:
            self.value_target.analyse_target_types(env)
5347
            self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type)
5348 5349 5350
            self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
        if self.tuple_target:
            self.tuple_target.analyse_target_types(env)
5351
            self.tuple_ref = ExprNodes.TempNode(self.tuple_target.pos, PyrexTypes.py_object_type)
5352 5353
            self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env)
        self.is_dict_flag.analyse_types(env)
5354 5355 5356 5357 5358

    def generate_function_definitions(self, env, code):
        self.dict_obj.generate_function_definitions(env, code)

    def generate_execution_code(self, code):
5359
        code.globalstate.use_utility_code(UtilityCode.load_cached("dict_iter", "Optimize.c"))
5360 5361
        self.dict_obj.generate_evaluation_code(code)

5362 5363 5364 5365 5366 5367 5368 5369
        assignments = []
        temp_addresses = []
        for var, result, target in [(self.key_ref, self.coerced_key_var, self.key_target),
                                    (self.value_ref, self.coerced_value_var, self.value_target),
                                    (self.tuple_ref, self.coerced_tuple_var, self.tuple_target)]:
            if target is None:
                addr = 'NULL'
            else:
5370 5371 5372
                assignments.append((var, result, target))
                var.allocate(code)
                addr = '&%s' % var.result()
5373 5374 5375 5376 5377
            temp_addresses.append(addr)

        result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
        code.putln("%s = __Pyx_dict_iter_next(%s, %s, &%s, %s, %s, %s, %s);" % (
            result_temp,
5378
            self.dict_obj.py_result(),
5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
            self.expected_size.result(),
            self.pos_index_var.result(),
            temp_addresses[0],
            temp_addresses[1],
            temp_addresses[2],
            self.is_dict_flag.result()
        ))
        code.putln("if (unlikely(%s == 0)) break;" % result_temp)
        code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos))
        code.funcstate.release_temp(result_temp)

        # evaluate all coercions before the assignments
5391 5392
        for var, result, target in assignments:
            code.put_gotref(var.result())
5393
        for var, result, target in assignments:
5394
            result.generate_evaluation_code(code)
5395
        for var, result, target in assignments:
5396
            target.generate_assignment_code(result, code)
5397
            var.release(code)
5398

Robert Bradshaw's avatar
Robert Bradshaw committed
5399
def ForStatNode(pos, **kw):
5400
    if 'iterator' in kw:
Robert Bradshaw's avatar
Robert Bradshaw committed
5401 5402 5403 5404
        return ForInStatNode(pos, **kw)
    else:
        return ForFromStatNode(pos, **kw)

5405
class ForInStatNode(LoopNode, StatNode):
William Stein's avatar
William Stein committed
5406 5407 5408 5409 5410 5411 5412
    #  for statement
    #
    #  target        ExprNode
    #  iterator      IteratorNode
    #  body          StatNode
    #  else_clause   StatNode
    #  item          NextNode       used internally
5413

5414
    child_attrs = ["target", "iterator", "body", "else_clause"]
5415
    item = None
5416

William Stein's avatar
William Stein committed
5417
    def analyse_declarations(self, env):
5418
        import ExprNodes
William Stein's avatar
William Stein committed
5419 5420 5421 5422
        self.target.analyse_target_declaration(env)
        self.body.analyse_declarations(env)
        if self.else_clause:
            self.else_clause.analyse_declarations(env)
5423
        self.item = ExprNodes.NextNode(self.iterator)
5424

William Stein's avatar
William Stein committed
5425 5426
    def analyse_expressions(self, env):
        self.target.analyse_target_types(env)
5427
        self.iterator.analyse_expressions(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
5428 5429 5430 5431
        if self.item is None:
            # Hack. Sometimes analyse_declarations not called.
            import ExprNodes
            self.item = ExprNodes.NextNode(self.iterator)
5432
        self.item.analyse_expressions(env)
5433 5434 5435 5436 5437 5438
        if (self.iterator.type.is_ptr or self.iterator.type.is_array) and \
            self.target.type.assignable_from(self.iterator.type):
            # C array slice optimization.
            pass
        else:
            self.item = self.item.coerce_to(self.target.type, env)
William Stein's avatar
William Stein committed
5439 5440 5441 5442 5443 5444 5445
        self.body.analyse_expressions(env)
        if self.else_clause:
            self.else_clause.analyse_expressions(env)

    def generate_execution_code(self, code):
        old_loop_labels = code.new_loop_labels()
        self.iterator.generate_evaluation_code(code)
Mark Florisson's avatar
Mark Florisson committed
5446
        code.putln("for (;;) {")
William Stein's avatar
William Stein committed
5447 5448 5449
        self.item.generate_evaluation_code(code)
        self.target.generate_assignment_code(self.item, code)
        self.body.generate_execution_code(code)
5450
        code.put_label(code.continue_label)
Mark Florisson's avatar
Mark Florisson committed
5451
        code.putln("}")
William Stein's avatar
William Stein committed
5452 5453
        break_label = code.break_label
        code.set_loop_labels(old_loop_labels)
5454

William Stein's avatar
William Stein committed
5455
        if self.else_clause:
5456 5457 5458 5459 5460 5461 5462
            # in nested loops, the 'else' block can contain a
            # 'continue' statement for the outer loop, but we may need
            # to generate cleanup code before taking that path, so we
            # intercept it here
            orig_continue_label = code.continue_label
            code.continue_label = code.new_label('outer_continue')

William Stein's avatar
William Stein committed
5463 5464 5465
            code.putln("/*else*/ {")
            self.else_clause.generate_execution_code(code)
            code.putln("}")
5466 5467 5468 5469 5470 5471 5472 5473 5474 5475

            if code.label_used(code.continue_label):
                code.put_goto(break_label)
                code.put_label(code.continue_label)
                self.iterator.generate_disposal_code(code)
                code.put_goto(orig_continue_label)
            code.set_loop_labels(old_loop_labels)

        if code.label_used(break_label):
            code.put_label(break_label)
William Stein's avatar
William Stein committed
5476
        self.iterator.generate_disposal_code(code)
5477
        self.iterator.free_temps(code)
William Stein's avatar
William Stein committed
5478

5479 5480 5481 5482 5483 5484 5485
    def generate_function_definitions(self, env, code):
        self.target.generate_function_definitions(env, code)
        self.iterator.generate_function_definitions(env, code)
        self.body.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)

5486 5487 5488 5489 5490 5491 5492 5493
    def annotate(self, code):
        self.target.annotate(code)
        self.iterator.annotate(code)
        self.body.annotate(code)
        if self.else_clause:
            self.else_clause.annotate(code)
        self.item.annotate(code)

William Stein's avatar
William Stein committed
5494

5495
class ForFromStatNode(LoopNode, StatNode):
William Stein's avatar
William Stein committed
5496 5497 5498 5499 5500 5501 5502
    #  for name from expr rel name rel expr
    #
    #  target        NameNode
    #  bound1        ExprNode
    #  relation1     string
    #  relation2     string
    #  bound2        ExprNode
5503
    #  step          ExprNode or None
William Stein's avatar
William Stein committed
5504 5505 5506 5507 5508
    #  body          StatNode
    #  else_clause   StatNode or None
    #
    #  Used internally:
    #
Robert Bradshaw's avatar
Robert Bradshaw committed
5509
    #  from_range         bool
5510
    #  is_py_target       bool
5511
    #  loopvar_node       ExprNode (usually a NameNode or temp node)
William Stein's avatar
William Stein committed
5512
    #  py_loopvar_node    PyTempNode or None
5513
    child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
5514 5515

    is_py_target = False
5516
    loopvar_node = None
5517
    py_loopvar_node = None
Robert Bradshaw's avatar
Robert Bradshaw committed
5518
    from_range = False
5519

5520 5521 5522 5523 5524 5525 5526
    gil_message = "For-loop using object bounds or target"

    def nogil_check(self, env):
        for x in (self.target, self.bound1, self.bound2):
            if x.type.is_pyobject:
                self.gil_error()

Robert Bradshaw's avatar
Robert Bradshaw committed
5527 5528 5529 5530 5531
    def analyse_declarations(self, env):
        self.target.analyse_target_declaration(env)
        self.body.analyse_declarations(env)
        if self.else_clause:
            self.else_clause.analyse_declarations(env)
5532

William Stein's avatar
William Stein committed
5533 5534 5535 5536 5537
    def analyse_expressions(self, env):
        import ExprNodes
        self.target.analyse_target_types(env)
        self.bound1.analyse_types(env)
        self.bound2.analyse_types(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
5538 5539 5540 5541
        if self.step is not None:
            if isinstance(self.step, ExprNodes.UnaryMinusNode):
                warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
            self.step.analyse_types(env)
5542

Robert Bradshaw's avatar
Robert Bradshaw committed
5543
        target_type = self.target.type
5544
        if self.target.type.is_numeric:
Robert Bradshaw's avatar
Robert Bradshaw committed
5545
            loop_type = self.target.type
5546
        else:
Robert Bradshaw's avatar
Robert Bradshaw committed
5547 5548 5549 5550 5551 5552 5553 5554 5555
            loop_type = PyrexTypes.c_int_type
            if not self.bound1.type.is_pyobject:
                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
            if not self.bound2.type.is_pyobject:
                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
            if self.step is not None and not self.step.type.is_pyobject:
                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
        self.bound1 = self.bound1.coerce_to(loop_type, env)
        self.bound2 = self.bound2.coerce_to(loop_type, env)
Robert Bradshaw's avatar
Robert Bradshaw committed
5556 5557
        if not self.bound2.is_literal:
            self.bound2 = self.bound2.coerce_to_temp(env)
5558
        if self.step is not None:
5559
            self.step = self.step.coerce_to(loop_type, env)
Robert Bradshaw's avatar
Robert Bradshaw committed
5560 5561
            if not self.step.is_literal:
                self.step = self.step.coerce_to_temp(env)
Robert Bradshaw's avatar
Robert Bradshaw committed
5562

William Stein's avatar
William Stein committed
5563
        target_type = self.target.type
5564
        if not (target_type.is_pyobject or target_type.is_numeric):
5565
            error(self.target.pos,
Robert Bradshaw's avatar
Robert Bradshaw committed
5566
                "for-from loop variable must be c numeric type or Python object")
5567
        if target_type.is_numeric:
Robert Bradshaw's avatar
Robert Bradshaw committed
5568
            self.is_py_target = False
5569 5570
            if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
                raise error(self.pos, "Buffer indexing not allowed as for loop target.")
5571
            self.loopvar_node = self.target
William Stein's avatar
William Stein committed
5572 5573
            self.py_loopvar_node = None
        else:
Robert Bradshaw's avatar
Robert Bradshaw committed
5574 5575
            self.is_py_target = True
            c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
5576
            self.loopvar_node = c_loopvar_node
William Stein's avatar
William Stein committed
5577 5578 5579 5580 5581
            self.py_loopvar_node = \
                ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
        self.body.analyse_expressions(env)
        if self.else_clause:
            self.else_clause.analyse_expressions(env)
5582

William Stein's avatar
William Stein committed
5583 5584
    def generate_execution_code(self, code):
        old_loop_labels = code.new_loop_labels()
Robert Bradshaw's avatar
Robert Bradshaw committed
5585
        from_range = self.from_range
William Stein's avatar
William Stein committed
5586 5587 5588
        self.bound1.generate_evaluation_code(code)
        self.bound2.generate_evaluation_code(code)
        offset, incop = self.relation_table[self.relation1]
5589 5590
        if self.step is not None:
            self.step.generate_evaluation_code(code)
Magnus Lie Hetland's avatar
Magnus Lie Hetland committed
5591 5592
            step = self.step.result()
            incop = "%s=%s" % (incop[0], step)
5593 5594 5595 5596 5597
        import ExprNodes
        if isinstance(self.loopvar_node, ExprNodes.TempNode):
            self.loopvar_node.allocate(code)
        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
            self.py_loopvar_node.allocate(code)
5598
        if from_range:
Robert Bradshaw's avatar
Robert Bradshaw committed
5599
            loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
5600
        else:
Robert Bradshaw's avatar
Robert Bradshaw committed
5601
            loopvar_name = self.loopvar_node.result()
William Stein's avatar
William Stein committed
5602 5603
        code.putln(
            "for (%s = %s%s; %s %s %s; %s%s) {" % (
5604
                loopvar_name,
5605
                self.bound1.result(), offset,
Robert Bradshaw's avatar
Robert Bradshaw committed
5606
                loopvar_name, self.relation2, self.bound2.result(),
5607
                loopvar_name, incop))
William Stein's avatar
William Stein committed
5608 5609 5610
        if self.py_loopvar_node:
            self.py_loopvar_node.generate_evaluation_code(code)
            self.target.generate_assignment_code(self.py_loopvar_node, code)
Robert Bradshaw's avatar
Robert Bradshaw committed
5611 5612 5613
        elif from_range:
            code.putln("%s = %s;" % (
                            self.target.result(), loopvar_name))
William Stein's avatar
William Stein committed
5614 5615
        self.body.generate_execution_code(code)
        code.put_label(code.continue_label)
Robert Bradshaw's avatar
Robert Bradshaw committed
5616
        if self.py_loopvar_node:
5617 5618 5619
            # This mess is to make for..from loops with python targets behave
            # exactly like those with C targets with regards to re-assignment
            # of the loop variable.
5620
            import ExprNodes
5621
            if self.target.entry.is_pyglobal:
5622
                # We know target is a NameNode, this is the only ugly case.
5623
                target_node = ExprNodes.PyTempNode(self.target.pos, None)
5624 5625
                target_node.allocate(code)
                interned_cname = code.intern_identifier(self.target.entry.name)
5626
                code.globalstate.use_utility_code(ExprNodes.get_name_interned_utility_code)
5627
                code.putln("%s = __Pyx_GetName(%s, %s); %s" % (
5628
                                target_node.result(),
5629
                                Naming.module_cname,
5630 5631 5632
                                interned_cname,
                                code.error_goto_if_null(target_node.result(), self.target.pos)))
                code.put_gotref(target_node.result())
5633 5634 5635
            else:
                target_node = self.target
            from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, target_node, None)
5636 5637
            from_py_node.temp_code = loopvar_name
            from_py_node.generate_result_code(code)
5638
            if self.target.entry.is_pyglobal:
5639 5640
                code.put_decref(target_node.result(), target_node.type)
                target_node.release(code)
Robert Bradshaw's avatar
Robert Bradshaw committed
5641
        code.putln("}")
5642
        if self.py_loopvar_node:
5643 5644
            # This is potentially wasteful, but we don't want the semantics to
            # depend on whether or not the loop is a python type.
5645 5646
            self.py_loopvar_node.generate_evaluation_code(code)
            self.target.generate_assignment_code(self.py_loopvar_node, code)
5647 5648
        if from_range:
            code.funcstate.release_temp(loopvar_name)
William Stein's avatar
William Stein committed
5649 5650 5651 5652 5653 5654 5655 5656
        break_label = code.break_label
        code.set_loop_labels(old_loop_labels)
        if self.else_clause:
            code.putln("/*else*/ {")
            self.else_clause.generate_execution_code(code)
            code.putln("}")
        code.put_label(break_label)
        self.bound1.generate_disposal_code(code)
5657
        self.bound1.free_temps(code)
William Stein's avatar
William Stein committed
5658
        self.bound2.generate_disposal_code(code)
5659
        self.bound2.free_temps(code)
5660 5661 5662 5663
        if isinstance(self.loopvar_node, ExprNodes.TempNode):
            self.loopvar_node.release(code)
        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
            self.py_loopvar_node.release(code)
5664 5665
        if self.step is not None:
            self.step.generate_disposal_code(code)
5666
            self.step.free_temps(code)
5667

William Stein's avatar
William Stein committed
5668 5669 5670 5671 5672 5673 5674
    relation_table = {
        # {relop : (initial offset, increment op)}
        '<=': ("",   "++"),
        '<' : ("+1", "++"),
        '>=': ("",   "--"),
        '>' : ("-1", "--")
    }
5675 5676 5677 5678 5679 5680 5681 5682 5683 5684

    def generate_function_definitions(self, env, code):
        self.target.generate_function_definitions(env, code)
        self.bound1.generate_function_definitions(env, code)
        self.bound2.generate_function_definitions(env, code)
        if self.step is not None:
            self.step.generate_function_definitions(env, code)
        self.body.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)
5685

5686 5687 5688 5689 5690
    def annotate(self, code):
        self.target.annotate(code)
        self.bound1.annotate(code)
        self.bound2.annotate(code)
        if self.step:
5691
            self.step.annotate(code)
5692 5693 5694
        self.body.annotate(code)
        if self.else_clause:
            self.else_clause.annotate(code)
William Stein's avatar
William Stein committed
5695 5696


5697 5698 5699
class WithStatNode(StatNode):
    """
    Represents a Python with statement.
5700

5701
    Implemented by the WithTransform as follows:
5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718

        MGR = EXPR
        EXIT = MGR.__exit__
        VALUE = MGR.__enter__()
        EXC = True
        try:
            try:
                TARGET = VALUE  # optional
                BODY
            except:
                EXC = False
                if not EXIT(*EXCINFO):
                    raise
        finally:
            if EXC:
                EXIT(None, None, None)
            MGR = EXIT = VALUE = None
5719 5720
    """
    #  manager          The with statement manager object
5721
    #  target           ExprNode  the target lhs of the __enter__() call
5722
    #  body             StatNode
5723
    #  enter_call       ExprNode  the call to the __enter__() method
5724
    #  exit_var         String    the cname of the __exit__() method reference
5725

5726
    child_attrs = ["manager", "enter_call", "target", "body"]
5727

5728
    enter_call = None
5729 5730 5731

    def analyse_declarations(self, env):
        self.manager.analyse_declarations(env)
5732
        self.enter_call.analyse_declarations(env)
5733 5734 5735 5736
        self.body.analyse_declarations(env)

    def analyse_expressions(self, env):
        self.manager.analyse_types(env)
5737
        self.enter_call.analyse_types(env)
5738 5739
        self.body.analyse_expressions(env)

5740 5741
    def generate_function_definitions(self, env, code):
        self.manager.generate_function_definitions(env, code)
5742
        self.enter_call.generate_function_definitions(env, code)
5743 5744
        self.body.generate_function_definitions(env, code)

5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760
    def generate_execution_code(self, code):
        code.putln("/*with:*/ {")
        self.manager.generate_evaluation_code(code)
        self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
        code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
            self.exit_var,
            self.manager.py_result(),
            code.get_py_string_const(EncodedString('__exit__'), identifier=True),
            code.error_goto_if_null(self.exit_var, self.pos),
            ))
        code.put_gotref(self.exit_var)

        # need to free exit_var in the face of exceptions during setup
        old_error_label = code.new_error_label()
        intermediate_error_label = code.error_label

5761 5762 5763 5764
        self.enter_call.generate_evaluation_code(code)
        if not self.target:
            self.enter_call.generate_disposal_code(code)
            self.enter_call.free_temps(code)
5765 5766 5767 5768 5769
        else:
            # Otherwise, the node will be cleaned up by the
            # WithTargetAssignmentStatNode after assigning its result
            # to the target of the 'with' statement.
            pass
5770 5771 5772 5773 5774 5775
        self.manager.generate_disposal_code(code)
        self.manager.free_temps(code)

        code.error_label = old_error_label
        self.body.generate_execution_code(code)

5776 5777 5778 5779 5780 5781 5782
        if code.label_used(intermediate_error_label):
            step_over_label = code.new_label()
            code.put_goto(step_over_label)
            code.put_label(intermediate_error_label)
            code.put_decref_clear(self.exit_var, py_object_type)
            code.put_goto(old_error_label)
            code.put_label(step_over_label)
5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793

        code.funcstate.release_temp(self.exit_var)
        code.putln('}')

class WithTargetAssignmentStatNode(AssignmentNode):
    # The target assignment of the 'with' statement value (return
    # value of the __enter__() call).
    #
    # This is a special cased assignment that steals the RHS reference
    # and frees its temp.
    #
5794 5795 5796 5797 5798
    # lhs       ExprNode   the assignment target
    # rhs       CloneNode  a (coerced) CloneNode for the orig_rhs (not owned by this node)
    # orig_rhs  ExprNode   the original ExprNode of the rhs. this node will clean up the
    #                      temps of the orig_rhs. basically, it takes ownership of the node
    #                      when the WithStatNode is done with it.
5799

5800
    child_attrs = ["lhs"]
5801 5802 5803 5804

    def analyse_declarations(self, env):
        self.lhs.analyse_target_declaration(env)

5805
    def analyse_expressions(self, env):
5806 5807 5808 5809 5810 5811
        self.rhs.analyse_types(env)
        self.lhs.analyse_target_types(env)
        self.lhs.gil_assignment_check(env)
        self.rhs = self.rhs.coerce_to(self.lhs.type, env)

    def generate_execution_code(self, code):
5812 5813 5814 5815 5816
        if self.orig_rhs.type.is_pyobject:
            # make sure rhs gets freed on errors, see below
            old_error_label = code.new_error_label()
            intermediate_error_label = code.error_label

5817 5818 5819
        self.rhs.generate_evaluation_code(code)
        self.lhs.generate_assignment_code(self.rhs, code)

5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830
        if self.orig_rhs.type.is_pyobject:
            self.orig_rhs.generate_disposal_code(code)
            code.error_label = old_error_label
            if code.label_used(intermediate_error_label):
                step_over_label = code.new_label()
                code.put_goto(step_over_label)
                code.put_label(intermediate_error_label)
                self.orig_rhs.generate_disposal_code(code)
                code.put_goto(old_error_label)
                code.put_label(step_over_label)

5831
        self.orig_rhs.free_temps(code)
5832 5833 5834 5835 5836

    def annotate(self, code):
        self.lhs.annotate(code)
        self.rhs.annotate(code)

5837

William Stein's avatar
William Stein committed
5838 5839 5840 5841 5842 5843
class TryExceptStatNode(StatNode):
    #  try .. except statement
    #
    #  body             StatNode
    #  except_clauses   [ExceptClauseNode]
    #  else_clause      StatNode or None
5844

5845
    child_attrs = ["body", "except_clauses", "else_clause"]
5846

William Stein's avatar
William Stein committed
5847 5848 5849 5850 5851 5852
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
        for except_clause in self.except_clauses:
            except_clause.analyse_declarations(env)
        if self.else_clause:
            self.else_clause.analyse_declarations(env)
5853
        env.use_utility_code(reset_exception_utility_code)
5854

William Stein's avatar
William Stein committed
5855 5856
    def analyse_expressions(self, env):
        self.body.analyse_expressions(env)
5857
        default_clause_seen = 0
William Stein's avatar
William Stein committed
5858 5859
        for except_clause in self.except_clauses:
            except_clause.analyse_expressions(env)
5860 5861 5862 5863 5864
            if default_clause_seen:
                error(except_clause.pos, "default 'except:' must be last")
            if not except_clause.pattern:
                default_clause_seen = 1
        self.has_default_clause = default_clause_seen
William Stein's avatar
William Stein committed
5865 5866
        if self.else_clause:
            self.else_clause.analyse_expressions(env)
5867

5868
    nogil_check = Node.gil_error
5869 5870
    gil_message = "Try-except statement"

William Stein's avatar
William Stein committed
5871
    def generate_execution_code(self, code):
5872
        old_return_label = code.return_label
5873
        old_break_label = code.break_label
5874
        old_continue_label = code.continue_label
William Stein's avatar
William Stein committed
5875 5876
        old_error_label = code.new_error_label()
        our_error_label = code.error_label
5877 5878 5879
        except_end_label = code.new_label('exception_handled')
        except_error_label = code.new_label('except_error')
        except_return_label = code.new_label('except_return')
5880
        try_return_label = code.new_label('try_return')
5881
        try_break_label = code.new_label('try_break')
5882
        try_continue_label = code.new_label('try_continue')
5883
        try_end_label = code.new_label('try_end')
5884

5885 5886
        exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False)
                         for i in xrange(3)]
5887 5888
        code.putln("{")
        code.putln("__Pyx_ExceptionSave(%s);" %
5889 5890
                   ', '.join(['&%s' % var for var in exc_save_vars]))
        for var in exc_save_vars:
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
5891
            code.put_xgotref(var)
William Stein's avatar
William Stein committed
5892 5893
        code.putln(
            "/*try:*/ {")
5894
        code.return_label = try_return_label
5895
        code.break_label = try_break_label
5896
        code.continue_label = try_continue_label
William Stein's avatar
William Stein committed
5897 5898 5899
        self.body.generate_execution_code(code)
        code.putln(
            "}")
5900
        temps_to_clean_up = code.funcstate.all_free_managed_temps()
5901 5902
        code.error_label = except_error_label
        code.return_label = except_return_label
William Stein's avatar
William Stein committed
5903 5904 5905 5906 5907 5908
        if self.else_clause:
            code.putln(
                "/*else:*/ {")
            self.else_clause.generate_execution_code(code)
            code.putln(
                "}")
5909
        for var in exc_save_vars:
5910
            code.put_xdecref_clear(var, py_object_type)
5911
        code.put_goto(try_end_label)
5912 5913
        if code.label_used(try_return_label):
            code.put_label(try_return_label)
Stefan Behnel's avatar
Stefan Behnel committed
5914 5915
            for var in exc_save_vars:
                code.put_xgiveref(var)
5916
            code.putln("__Pyx_ExceptionReset(%s);" %
5917
                       ', '.join(exc_save_vars))
5918
            code.put_goto(old_return_label)
William Stein's avatar
William Stein committed
5919
        code.put_label(our_error_label)
5920 5921
        for temp_name, type in temps_to_clean_up:
            code.put_xdecref_clear(temp_name, type)
William Stein's avatar
William Stein committed
5922
        for except_clause in self.except_clauses:
5923 5924
            except_clause.generate_handling_code(code, except_end_label)

5925 5926 5927 5928
        error_label_used = code.label_used(except_error_label)
        if error_label_used or not self.has_default_clause:
            if error_label_used:
                code.put_label(except_error_label)
Stefan Behnel's avatar
Stefan Behnel committed
5929 5930
            for var in exc_save_vars:
                code.put_xgiveref(var)
Stefan Behnel's avatar
Stefan Behnel committed
5931
            code.putln("__Pyx_ExceptionReset(%s);" %
5932
                       ', '.join(exc_save_vars))
5933 5934
            code.put_goto(old_error_label)

5935 5936 5937 5938 5939 5940
        for exit_label, old_label in zip(
            [try_break_label, try_continue_label, except_return_label],
            [old_break_label, old_continue_label, old_return_label]):

            if code.label_used(exit_label):
                code.put_label(exit_label)
Stefan Behnel's avatar
Stefan Behnel committed
5941 5942
                for var in exc_save_vars:
                    code.put_xgiveref(var)
5943
                code.putln("__Pyx_ExceptionReset(%s);" %
5944
                           ', '.join(exc_save_vars))
5945
                code.put_goto(old_label)
5946 5947 5948

        if code.label_used(except_end_label):
            code.put_label(except_end_label)
Stefan Behnel's avatar
Stefan Behnel committed
5949 5950
            for var in exc_save_vars:
                code.put_xgiveref(var)
5951
            code.putln("__Pyx_ExceptionReset(%s);" %
5952
                       ', '.join(exc_save_vars))
5953 5954 5955
        code.put_label(try_end_label)
        code.putln("}")

5956 5957 5958
        for cname in exc_save_vars:
            code.funcstate.release_temp(cname)

5959
        code.return_label = old_return_label
5960
        code.break_label = old_break_label
5961
        code.continue_label = old_continue_label
5962
        code.error_label = old_error_label
William Stein's avatar
William Stein committed
5963

5964 5965 5966 5967 5968 5969 5970
    def generate_function_definitions(self, env, code):
        self.body.generate_function_definitions(env, code)
        for except_clause in self.except_clauses:
            except_clause.generate_function_definitions(env, code)
        if self.else_clause is not None:
            self.else_clause.generate_function_definitions(env, code)

5971 5972 5973 5974 5975 5976 5977
    def annotate(self, code):
        self.body.annotate(code)
        for except_node in self.except_clauses:
            except_node.annotate(code)
        if self.else_clause:
            self.else_clause.annotate(code)

William Stein's avatar
William Stein committed
5978 5979 5980 5981

class ExceptClauseNode(Node):
    #  Part of try ... except statement.
    #
5982
    #  pattern        [ExprNode]
William Stein's avatar
William Stein committed
5983 5984
    #  target         ExprNode or None
    #  body           StatNode
5985
    #  excinfo_target ResultRefNode or None   optional target for exception info
William Stein's avatar
William Stein committed
5986 5987 5988
    #  match_flag     string             result of exception match
    #  exc_value      ExcValueNode       used internally
    #  function_name  string             qualified name of enclosing function
5989
    #  exc_vars       (string * 3)       local exception variables
5990 5991 5992 5993

    # excinfo_target is never set by the parser, but can be set by a transform
    # in order to extract more extensive information about the exception as a
    # sys.exc_info()-style tuple into a target variable
5994

5995
    child_attrs = ["pattern", "target", "body", "exc_value", "excinfo_target"]
5996

5997
    exc_value = None
5998
    excinfo_target = None
5999

William Stein's avatar
William Stein committed
6000 6001 6002 6003
    def analyse_declarations(self, env):
        if self.target:
            self.target.analyse_target_declaration(env)
        self.body.analyse_declarations(env)
6004

William Stein's avatar
William Stein committed
6005 6006 6007 6008 6009
    def analyse_expressions(self, env):
        import ExprNodes
        genv = env.global_scope()
        self.function_name = env.qualified_name
        if self.pattern:
6010 6011 6012 6013
            # normalise/unpack self.pattern into a list
            for i, pattern in enumerate(self.pattern):
                pattern.analyse_expressions(env)
                self.pattern[i] = pattern.coerce_to_pyobject(env)
6014

William Stein's avatar
William Stein committed
6015
        if self.target:
6016
            self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
6017
            self.target.analyse_target_expression(env, self.exc_value)
6018 6019 6020
        if self.excinfo_target is not None:
            import ExprNodes
            self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
6021
                ExprNodes.ExcValueNode(pos=self.pos, env=env) for x in range(3)])
6022 6023
            self.excinfo_tuple.analyse_expressions(env)

William Stein's avatar
William Stein committed
6024
        self.body.analyse_expressions(env)
6025

William Stein's avatar
William Stein committed
6026 6027 6028
    def generate_handling_code(self, code, end_label):
        code.mark_pos(self.pos)
        if self.pattern:
6029 6030 6031 6032 6033
            exc_tests = []
            for pattern in self.pattern:
                pattern.generate_evaluation_code(code)
                exc_tests.append("PyErr_ExceptionMatches(%s)" % pattern.py_result())

6034
            match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
William Stein's avatar
William Stein committed
6035
            code.putln(
6036 6037 6038 6039
                "%s = %s;" % (match_flag, ' || '.join(exc_tests)))
            for pattern in self.pattern:
                pattern.generate_disposal_code(code)
                pattern.free_temps(code)
William Stein's avatar
William Stein committed
6040 6041
            code.putln(
                "if (%s) {" %
6042 6043
                    match_flag)
            code.funcstate.release_temp(match_flag)
William Stein's avatar
William Stein committed
6044
        else:
6045
            code.putln("/*except:*/ {")
6046

Stefan Behnel's avatar
fix  
Stefan Behnel committed
6047
        if not getattr(self.body, 'stats', True) and \
Stefan Behnel's avatar
Stefan Behnel committed
6048
                self.excinfo_target is None and self.target is None:
Stefan Behnel's avatar
Stefan Behnel committed
6049 6050
            # most simple case: no exception variable, empty body (pass)
            # => reset the exception state, done
6051 6052 6053 6054
            code.putln("PyErr_Restore(0,0,0);")
            code.put_goto(end_label)
            code.putln("}")
            return
6055

6056 6057 6058
        exc_vars = [code.funcstate.allocate_temp(py_object_type,
                                                 manage_ref=True)
                    for i in xrange(3)]
6059
        code.put_add_traceback(self.function_name)
William Stein's avatar
William Stein committed
6060
        # We always have to fetch the exception value even if
6061
        # there is no target, because this also normalises the
William Stein's avatar
William Stein committed
6062
        # exception and stores it in the thread state.
6063 6064
        code.globalstate.use_utility_code(get_exception_utility_code)
        exc_args = "&%s, &%s, &%s" % tuple(exc_vars)
6065 6066
        code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
            code.error_goto(self.pos)))
6067
        for x in exc_vars:
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
6068
            code.put_gotref(x)
William Stein's avatar
William Stein committed
6069
        if self.target:
6070
            self.exc_value.set_var(exc_vars[1])
6071
            self.exc_value.generate_evaluation_code(code)
William Stein's avatar
William Stein committed
6072
            self.target.generate_assignment_code(self.exc_value, code)
6073
        if self.excinfo_target is not None:
6074 6075
            for tempvar, node in zip(exc_vars, self.excinfo_tuple.args):
                node.set_var(tempvar)
6076
            self.excinfo_tuple.generate_evaluation_code(code)
6077
            self.excinfo_target.result_code = self.excinfo_tuple.result()
6078

6079 6080 6081 6082
        old_break_label, old_continue_label = code.break_label, code.continue_label
        code.break_label = code.new_label('except_break')
        code.continue_label = code.new_label('except_continue')

6083
        old_exc_vars = code.funcstate.exc_vars
6084
        code.funcstate.exc_vars = exc_vars
William Stein's avatar
William Stein committed
6085
        self.body.generate_execution_code(code)
6086
        code.funcstate.exc_vars = old_exc_vars
6087 6088
        if self.excinfo_target is not None:
            self.excinfo_tuple.generate_disposal_code(code)
6089
        for var in exc_vars:
6090
            code.put_decref_clear(var, py_object_type)
6091
        code.put_goto(end_label)
6092

Robert Bradshaw's avatar
Robert Bradshaw committed
6093 6094
        if code.label_used(code.break_label):
            code.put_label(code.break_label)
6095 6096
            if self.excinfo_target is not None:
                self.excinfo_tuple.generate_disposal_code(code)
6097
            for var in exc_vars:
6098
                code.put_decref_clear(var, py_object_type)
Robert Bradshaw's avatar
Robert Bradshaw committed
6099 6100
            code.put_goto(old_break_label)
        code.break_label = old_break_label
6101 6102 6103

        if code.label_used(code.continue_label):
            code.put_label(code.continue_label)
6104 6105
            if self.excinfo_target is not None:
                self.excinfo_tuple.generate_disposal_code(code)
6106
            for var in exc_vars:
6107
                code.put_decref_clear(var, py_object_type)
6108 6109
            code.put_goto(old_continue_label)
        code.continue_label = old_continue_label
6110

6111 6112
        if self.excinfo_target is not None:
            self.excinfo_tuple.free_temps(code)
6113 6114
        for temp in exc_vars:
            code.funcstate.release_temp(temp)
6115

William Stein's avatar
William Stein committed
6116 6117 6118
        code.putln(
            "}")

6119 6120 6121 6122
    def generate_function_definitions(self, env, code):
        if self.target is not None:
            self.target.generate_function_definitions(env, code)
        self.body.generate_function_definitions(env, code)
6123

6124
    def annotate(self, code):
6125
        if self.pattern:
6126 6127
            for pattern in self.pattern:
                pattern.annotate(code)
6128 6129 6130 6131
        if self.target:
            self.target.annotate(code)
        self.body.annotate(code)

William Stein's avatar
William Stein committed
6132 6133 6134 6135 6136 6137

class TryFinallyStatNode(StatNode):
    #  try ... finally statement
    #
    #  body             StatNode
    #  finally_clause   StatNode
6138
    #
William Stein's avatar
William Stein committed
6139 6140 6141 6142 6143 6144 6145 6146
    #  The plan is that we funnel all continue, break
    #  return and error gotos into the beginning of the
    #  finally block, setting a variable to remember which
    #  one we're doing. At the end of the finally block, we
    #  switch on the variable to figure out where to go.
    #  In addition, if we're doing an error, we save the
    #  exception on entry to the finally block and restore
    #  it on exit.
6147

6148
    child_attrs = ["body", "finally_clause"]
6149

6150
    preserve_exception = 1
6151

6152 6153 6154
    # handle exception case, in addition to return/break/continue
    handle_error_case = True

William Stein's avatar
William Stein committed
6155 6156 6157 6158
    disallow_continue_in_try_finally = 0
    # There doesn't seem to be any point in disallowing
    # continue in the try block, since we have no problem
    # handling it.
6159

6160 6161
    is_try_finally_in_nogil = False

6162 6163 6164 6165
    def create_analysed(pos, env, body, finally_clause):
        node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
        return node
    create_analysed = staticmethod(create_analysed)
6166

William Stein's avatar
William Stein committed
6167 6168 6169
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
        self.finally_clause.analyse_declarations(env)
6170

William Stein's avatar
William Stein committed
6171 6172 6173
    def analyse_expressions(self, env):
        self.body.analyse_expressions(env)
        self.finally_clause.analyse_expressions(env)
6174

6175
    nogil_check = Node.gil_error
6176 6177
    gil_message = "Try-finally statement"

William Stein's avatar
William Stein committed
6178 6179 6180 6181 6182
    def generate_execution_code(self, code):
        old_error_label = code.error_label
        old_labels = code.all_new_labels()
        new_labels = code.get_all_labels()
        new_error_label = code.error_label
6183 6184
        if not self.handle_error_case:
            code.error_label = old_error_label
William Stein's avatar
William Stein committed
6185
        catch_label = code.new_label()
6186 6187 6188

        code.putln("/*try:*/ {")

William Stein's avatar
William Stein committed
6189
        if self.disallow_continue_in_try_finally:
6190 6191
            was_in_try_finally = code.funcstate.in_try_finally
            code.funcstate.in_try_finally = 1
6192

William Stein's avatar
William Stein committed
6193
        self.body.generate_execution_code(code)
6194

William Stein's avatar
William Stein committed
6195
        if self.disallow_continue_in_try_finally:
6196
            code.funcstate.in_try_finally = was_in_try_finally
6197 6198 6199

        code.putln("}")

6200
        temps_to_clean_up = code.funcstate.all_free_managed_temps()
6201
        code.mark_pos(self.finally_clause.pos)
6202 6203
        code.putln("/*finally:*/ {")

6204 6205 6206 6207 6208 6209 6210 6211
        cases_used = []
        error_label_used = 0
        for i, new_label in enumerate(new_labels):
            if new_label in code.labels_used:
                cases_used.append(i)
                if new_label == new_error_label:
                    error_label_used = 1
                    error_label_case = i
6212

6213
        if cases_used:
6214 6215
            code.putln("int __pyx_why;")

6216
            if error_label_used and self.preserve_exception:
6217 6218 6219
                if self.is_try_finally_in_nogil:
                    code.declare_gilstate()

6220 6221 6222 6223
                code.putln("PyObject *%s, *%s, *%s;" % Naming.exc_vars)
                code.putln("int %s;" % Naming.exc_lineno_name)
                exc_var_init_zero = ''.join(
                                ["%s = 0; " % var for var in Naming.exc_vars])
6224 6225 6226 6227
                exc_var_init_zero += '%s = 0;' % Naming.exc_lineno_name
                code.putln(exc_var_init_zero)
            else:
                exc_var_init_zero = None
6228

6229
            code.use_label(catch_label)
6230
            code.putln("__pyx_why = 0; goto %s;" % catch_label)
6231 6232
            for i in cases_used:
                new_label = new_labels[i]
Stefan Behnel's avatar
Stefan Behnel committed
6233
                #if new_label and new_label != "<try>":
6234
                if new_label == new_error_label and self.preserve_exception:
6235
                    self.put_error_catcher(code,
6236
                        new_error_label, i+1, catch_label, temps_to_clean_up)
6237
                else:
6238 6239 6240
                    code.put('%s: ' % new_label)
                    if exc_var_init_zero:
                        code.putln(exc_var_init_zero)
6241
                    code.putln("__pyx_why = %s; goto %s;" % (i+1, catch_label))
6242
            code.put_label(catch_label)
6243

William Stein's avatar
William Stein committed
6244
        code.set_all_labels(old_labels)
6245 6246 6247
        if error_label_used:
            code.new_error_label()
            finally_error_label = code.error_label
6248

William Stein's avatar
William Stein committed
6249
        self.finally_clause.generate_execution_code(code)
6250

6251 6252 6253
        if error_label_used:
            if finally_error_label in code.labels_used and self.preserve_exception:
                over_label = code.new_label()
6254
                code.put_goto(over_label)
6255
                code.put_label(finally_error_label)
6256

6257
                code.putln("if (__pyx_why == %d) {" % (error_label_case + 1))
6258 6259
                if self.is_try_finally_in_nogil:
                    code.put_ensure_gil(declare_gilstate=False)
6260 6261
                for var in Naming.exc_vars:
                    code.putln("Py_XDECREF(%s);" % var)
6262 6263
                if self.is_try_finally_in_nogil:
                    code.put_release_ensured_gil()
6264
                code.putln("}")
6265

6266 6267
                code.put_goto(old_error_label)
                code.put_label(over_label)
6268

6269
            code.error_label = old_error_label
6270

6271 6272
        if cases_used:
            code.putln(
William Stein's avatar
William Stein committed
6273
                "switch (__pyx_why) {")
6274 6275 6276
            for i in cases_used:
                old_label = old_labels[i]
                if old_label == old_error_label and self.preserve_exception:
William Stein's avatar
William Stein committed
6277 6278
                    self.put_error_uncatcher(code, i+1, old_error_label)
                else:
6279
                    code.use_label(old_label)
6280 6281
                    code.putln("case %s: goto %s;" % (i+1, old_label))

6282
            # End the switch
6283
            code.putln(
6284
                "}")
6285 6286

        # End finally
William Stein's avatar
William Stein committed
6287 6288 6289
        code.putln(
            "}")

6290 6291 6292 6293
    def generate_function_definitions(self, env, code):
        self.body.generate_function_definitions(env, code)
        self.finally_clause.generate_function_definitions(env, code)

6294 6295
    def put_error_catcher(self, code, error_label, i, catch_label,
                          temps_to_clean_up):
6296
        code.globalstate.use_utility_code(restore_exception_utility_code)
6297 6298 6299 6300 6301 6302
        code.putln("%s: {" % error_label)
        code.putln("__pyx_why = %s;" % i)

        if self.is_try_finally_in_nogil:
            code.put_ensure_gil(declare_gilstate=False)

6303 6304
        for temp_name, type in temps_to_clean_up:
            code.put_xdecref_clear(temp_name, type)
6305 6306 6307 6308 6309 6310 6311

        code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % Naming.exc_vars)
        code.putln("%s = %s;" % (Naming.exc_lineno_name, Naming.lineno_cname))

        if self.is_try_finally_in_nogil:
            code.put_release_ensured_gil()

6312
        code.put_goto(catch_label)
Robert Bradshaw's avatar
Robert Bradshaw committed
6313
        code.putln("}")
6314

William Stein's avatar
William Stein committed
6315
    def put_error_uncatcher(self, code, i, error_label):
6316
        code.globalstate.use_utility_code(restore_exception_utility_code)
William Stein's avatar
William Stein committed
6317
        code.putln(
6318
            "case %s: {" % i)
6319 6320 6321 6322 6323 6324 6325 6326 6327 6328

        if self.is_try_finally_in_nogil:
            code.put_ensure_gil(declare_gilstate=False)

        code.putln("__Pyx_ErrRestore(%s, %s, %s);" % Naming.exc_vars)
        code.putln("%s = %s;" % (Naming.lineno_cname, Naming.exc_lineno_name))

        if self.is_try_finally_in_nogil:
            code.put_release_ensured_gil()

6329
        for var in Naming.exc_vars:
William Stein's avatar
William Stein committed
6330
            code.putln(
6331
                   "%s = 0;" % var)
6332

6333
        code.put_goto(error_label)
William Stein's avatar
William Stein committed
6334 6335 6336
        code.putln(
            "}")

6337 6338 6339 6340
    def annotate(self, code):
        self.body.annotate(code)
        self.finally_clause.annotate(code)

William Stein's avatar
William Stein committed
6341

6342 6343 6344 6345 6346 6347 6348 6349 6350 6351
class NogilTryFinallyStatNode(TryFinallyStatNode):
    """
    A try/finally statement that may be used in nogil code sections.
    """

    preserve_exception = False
    nogil_check = None


class GILStatNode(NogilTryFinallyStatNode):
6352 6353 6354
    #  'with gil' or 'with nogil' statement
    #
    #   state   string   'gil' or 'nogil'
6355

6356 6357 6358 6359 6360 6361
    def __init__(self, pos, state, body):
        self.state = state
        TryFinallyStatNode.__init__(self, pos,
            body = body,
            finally_clause = GILExitNode(pos, state = state))

6362 6363 6364 6365
    def analyse_declarations(self, env):
        env._in_with_gil_block = (self.state == 'gil')
        if self.state == 'gil':
            env.has_with_gil_block = True
6366

6367 6368
        return super(GILStatNode, self).analyse_declarations(env)

6369
    def analyse_expressions(self, env):
6370 6371
        env.use_utility_code(
            UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
6372
        was_nogil = env.nogil
6373
        env.nogil = self.state == 'nogil'
6374 6375 6376
        TryFinallyStatNode.analyse_expressions(self, env)
        env.nogil = was_nogil

6377
    def generate_execution_code(self, code):
Stefan Behnel's avatar
Stefan Behnel committed
6378
        code.mark_pos(self.pos)
6379
        code.begin_block()
6380

6381
        if self.state == 'gil':
6382
            code.put_ensure_gil()
6383
        else:
6384 6385
            code.put_release_gil()

6386
        TryFinallyStatNode.generate_execution_code(self, code)
6387
        code.end_block()
6388 6389 6390


class GILExitNode(StatNode):
6391 6392 6393 6394 6395
    """
    Used as the 'finally' block in a GILStatNode

    state   string   'gil' or 'nogil'
    """
6396

6397 6398
    child_attrs = []

6399 6400 6401 6402 6403
    def analyse_expressions(self, env):
        pass

    def generate_execution_code(self, code):
        if self.state == 'gil':
6404
            code.put_release_ensured_gil()
6405
        else:
6406
            code.put_acquire_gil()
6407 6408


6409 6410 6411 6412 6413 6414 6415
class EnsureGILNode(GILExitNode):
    """
    Ensure the GIL in nogil functions for cleanup before returning.
    """

    def generate_execution_code(self, code):
        code.put_ensure_gil(declare_gilstate=False)
6416

6417 6418 6419 6420 6421 6422
utility_code_for_cimports = {
    # utility code (or inlining c) in a pxd (or pyx) file.
    # TODO: Consider a generic user-level mechanism for importing
    'cpython.array'         : ("ArrayAPI", "arrayarray.h"),
    'cpython.array.array'   : ("ArrayAPI", "arrayarray.h"),
}
6423

William Stein's avatar
William Stein committed
6424 6425 6426 6427 6428
class CImportStatNode(StatNode):
    #  cimport statement
    #
    #  module_name   string           Qualified name of module being imported
    #  as_name       string or None   Name specified in "as" clause, if any
6429 6430

    child_attrs = []
6431

William Stein's avatar
William Stein committed
6432
    def analyse_declarations(self, env):
6433 6434 6435
        if not env.is_module_scope:
            error(self.pos, "cimport only allowed at module level")
            return
William Stein's avatar
William Stein committed
6436 6437
        module_scope = env.find_module(self.module_name, self.pos)
        if "." in self.module_name:
6438
            names = [EncodedString(name) for name in self.module_name.split(".")]
William Stein's avatar
William Stein committed
6439 6440 6441 6442 6443 6444 6445 6446 6447 6448
            top_name = names[0]
            top_module_scope = env.context.find_submodule(top_name)
            module_scope = top_module_scope
            for name in names[1:]:
                submodule_scope = module_scope.find_submodule(name)
                module_scope.declare_module(name, submodule_scope, self.pos)
                module_scope = submodule_scope
            if self.as_name:
                env.declare_module(self.as_name, module_scope, self.pos)
            else:
6449
                env.add_imported_module(module_scope)
William Stein's avatar
William Stein committed
6450 6451 6452 6453
                env.declare_module(top_name, top_module_scope, self.pos)
        else:
            name = self.as_name or self.module_name
            env.declare_module(name, module_scope, self.pos)
6454 6455 6456
        if self.module_name in utility_code_for_cimports:
            env.use_utility_code(UtilityCode.load_cached(
                *utility_code_for_cimports[self.module_name]))
William Stein's avatar
William Stein committed
6457 6458 6459

    def analyse_expressions(self, env):
        pass
6460

William Stein's avatar
William Stein committed
6461 6462
    def generate_execution_code(self, code):
        pass
6463

William Stein's avatar
William Stein committed
6464 6465 6466 6467

class FromCImportStatNode(StatNode):
    #  from ... cimport statement
    #
6468 6469
    #  module_name     string                        Qualified name of module
    #  imported_names  [(pos, name, as_name, kind)]  Names to be imported
6470

6471 6472
    child_attrs = []

William Stein's avatar
William Stein committed
6473
    def analyse_declarations(self, env):
6474 6475 6476
        if not env.is_module_scope:
            error(self.pos, "cimport only allowed at module level")
            return
William Stein's avatar
William Stein committed
6477 6478
        module_scope = env.find_module(self.module_name, self.pos)
        env.add_imported_module(module_scope)
6479
        for pos, name, as_name, kind in self.imported_names:
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6480 6481 6482 6483
            if name == "*":
                for local_name, entry in module_scope.entries.items():
                    env.add_imported_entry(local_name, entry, pos)
            else:
6484 6485 6486 6487
                entry = module_scope.lookup(name)
                if entry:
                    if kind and not self.declaration_matches(entry, kind):
                        entry.redeclared(pos)
6488
                    entry.used = 1
6489 6490 6491 6492 6493 6494 6495 6496
                else:
                    if kind == 'struct' or kind == 'union':
                        entry = module_scope.declare_struct_or_union(name,
                            kind = kind, scope = None, typedef_flag = 0, pos = pos)
                    elif kind == 'class':
                        entry = module_scope.declare_c_class(name, pos = pos,
                            module_name = self.module_name)
                    else:
6497 6498 6499 6500 6501 6502
                        submodule_scope = env.context.find_module(name, relative_to = module_scope, pos = self.pos)
                        if submodule_scope.parent_module is module_scope:
                            env.declare_module(as_name or name, submodule_scope, self.pos)
                        else:
                            error(pos, "Name '%s' not declared in module '%s'"
                                % (name, self.module_name))
6503

Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6504 6505 6506
                if entry:
                    local_name = as_name or name
                    env.add_imported_entry(local_name, entry, pos)
6507 6508 6509 6510 6511

        if self.module_name.startswith('cpython'): # enough for now
            if self.module_name in utility_code_for_cimports:
                env.use_utility_code(UtilityCode.load_cached(
                    *utility_code_for_cimports[self.module_name]))
6512
            for _, name, _, _ in self.imported_names:
6513 6514 6515 6516
                fqname = '%s.%s' % (self.module_name, name)
                if fqname in utility_code_for_cimports:
                    env.use_utility_code(UtilityCode.load_cached(
                        *utility_code_for_cimports[fqname]))
6517

6518
    def declaration_matches(self, entry, kind):
6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530
        if not entry.is_type:
            return 0
        type = entry.type
        if kind == 'class':
            if not type.is_extension_type:
                return 0
        else:
            if not type.is_struct_or_union:
                return 0
            if kind != type.kind:
                return 0
        return 1
William Stein's avatar
William Stein committed
6531 6532 6533

    def analyse_expressions(self, env):
        pass
6534

William Stein's avatar
William Stein committed
6535 6536 6537 6538 6539 6540 6541 6542 6543
    def generate_execution_code(self, code):
        pass


class FromImportStatNode(StatNode):
    #  from ... import statement
    #
    #  module           ImportNode
    #  items            [(string, NameNode)]
6544
    #  interned_items   [(string, NameNode, ExprNode)]
William Stein's avatar
William Stein committed
6545
    #  item             PyTempNode            used internally
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6546
    #  import_star      boolean               used internally
6547 6548

    child_attrs = ["module"]
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6549
    import_star = 0
6550

William Stein's avatar
William Stein committed
6551
    def analyse_declarations(self, env):
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6552 6553 6554 6555 6556 6557 6558 6559 6560
        for name, target in self.items:
            if name == "*":
                if not env.is_module_scope:
                    error(self.pos, "import * only allowed at module level")
                    return
                env.has_import_star = 1
                self.import_star = 1
            else:
                target.analyse_target_declaration(env)
6561

William Stein's avatar
William Stein committed
6562 6563 6564
    def analyse_expressions(self, env):
        import ExprNodes
        self.module.analyse_expressions(env)
6565
        self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
William Stein's avatar
William Stein committed
6566 6567
        self.interned_items = []
        for name, target in self.items:
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6568 6569 6570
            if name == '*':
                for _, entry in env.entries.items():
                    if not entry.is_type and entry.type.is_extension_type:
6571
                        env.use_utility_code(UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c"))
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6572 6573
                        break
            else:
6574
                entry =  env.lookup(target.name)
6575 6576
                # check whether or not entry is already cimported
                if (entry.is_type and entry.type.name == name
Stefan Behnel's avatar
Stefan Behnel committed
6577
                        and hasattr(entry.type, 'module_name')):
6578 6579 6580 6581 6582 6583 6584 6585 6586 6587
                    if entry.type.module_name == self.module.module_name.value:
                        # cimported with absolute name
                        continue
                    try:
                        # cimported with relative name
                        module = env.find_module(self.module.module_name.value,
                                                 pos=None)
                        if entry.type.module_name == module.qualified_name:
                            continue
                    except AttributeError:
6588
                        pass
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6589
                target.analyse_target_expression(env, None)
6590 6591 6592 6593
                if target.type is py_object_type:
                    coerced_item = None
                else:
                    coerced_item = self.item.coerce_to(target.type, env)
6594
                self.interned_items.append((name, target, coerced_item))
6595 6596
        if self.interned_items:
            env.use_utility_code(raise_import_error_utility_code)
6597

William Stein's avatar
William Stein committed
6598 6599
    def generate_execution_code(self, code):
        self.module.generate_evaluation_code(code)
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
6600 6601 6602 6603 6604 6605
        if self.import_star:
            code.putln(
                'if (%s(%s) < 0) %s;' % (
                    Naming.import_star,
                    self.module.py_result(),
                    code.error_goto(self.pos)))
6606 6607
        item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
        self.item.set_cname(item_temp)
6608 6609
        for name, target, coerced_item in self.interned_items:
            cname = code.intern_identifier(name)
6610
            code.putln(
6611
                '%s = PyObject_GetAttr(%s, %s);' % (
6612
                    item_temp,
6613
                    self.module.py_result(),
6614 6615 6616 6617 6618 6619 6620
                    cname))
            code.putln('if (%s == NULL) {' % item_temp)
            code.putln(
                'if (PyErr_ExceptionMatches(PyExc_AttributeError)) '
                '__Pyx_RaiseImportError(%s);' % cname)
            code.putln(code.error_goto_if_null(item_temp, self.pos))
            code.putln('}')
6621
            code.put_gotref(item_temp)
6622 6623 6624 6625 6626 6627
            if coerced_item is None:
                target.generate_assignment_code(self.item, code)
            else:
                coerced_item.allocate_temp_result(code)
                coerced_item.generate_result_code(code)
                target.generate_assignment_code(coerced_item, code)
6628 6629
            code.put_decref_clear(item_temp, py_object_type)
        code.funcstate.release_temp(item_temp)
William Stein's avatar
William Stein committed
6630
        self.module.generate_disposal_code(code)
6631
        self.module.free_temps(code)
William Stein's avatar
William Stein committed
6632

6633

Mark Florisson's avatar
Mark Florisson committed
6634 6635 6636 6637 6638 6639 6640 6641 6642 6643
class ParallelNode(Node):
    """
    Base class for cython.parallel constructs.
    """

    nogil_check = None


class ParallelStatNode(StatNode, ParallelNode):
    """
6644
    Base class for 'with cython.parallel.parallel():' and 'for i in prange():'.
Mark Florisson's avatar
Mark Florisson committed
6645 6646 6647 6648 6649

    assignments     { Entry(var) : (var.pos, inplace_operator_or_None) }
                    assignments to variables in this parallel section

    parent          parent ParallelStatNode or None
6650 6651 6652
    is_parallel     indicates whether this node is OpenMP parallel
                    (true for #pragma omp parallel for and
                              #pragma omp parallel)
Mark Florisson's avatar
Mark Florisson committed
6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663

    is_parallel is true for:

        #pragma omp parallel
        #pragma omp parallel for

    sections, but NOT for

        #pragma omp for

    We need this to determine the sharing attributes.
6664 6665 6666

    privatization_insertion_point   a code insertion point used to make temps
                                    private (esp. the "nsteps" temp)
6667 6668 6669 6670

    args         tuple          the arguments passed to the parallel construct
    kwargs       DictNode       the keyword arguments passed to the parallel
                                construct (replaced by its compile time value)
Mark Florisson's avatar
Mark Florisson committed
6671 6672
    """

6673
    child_attrs = ['body', 'num_threads']
Mark Florisson's avatar
Mark Florisson committed
6674 6675 6676 6677

    body = None

    is_prange = False
6678
    is_nested_prange = False
Mark Florisson's avatar
Mark Florisson committed
6679

6680
    error_label_used = False
6681

6682
    num_threads = None
6683
    chunksize = None
6684

6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701
    parallel_exc = (
        Naming.parallel_exc_type,
        Naming.parallel_exc_value,
        Naming.parallel_exc_tb,
    )

    parallel_pos_info = (
        Naming.parallel_filename,
        Naming.parallel_lineno,
        Naming.parallel_clineno,
    )

    pos_info = (
        Naming.filename_cname,
        Naming.lineno_cname,
        Naming.clineno_cname,
    )
6702

6703 6704
    critical_section_counter = 0

Mark Florisson's avatar
Mark Florisson committed
6705 6706
    def __init__(self, pos, **kwargs):
        super(ParallelStatNode, self).__init__(pos, **kwargs)
6707 6708

        # All assignments in this scope
Mark Florisson's avatar
Mark Florisson committed
6709 6710
        self.assignments = kwargs.get('assignments') or {}

6711 6712 6713 6714
        # All seen closure cnames and their temporary cnames
        self.seen_closure_vars = set()

        # Dict of variables that should be declared (first|last|)private or
6715 6716
        # reduction { Entry: (op, lastprivate) }.
        # If op is not None, it's a reduction.
6717
        self.privates = {}
Mark Florisson's avatar
Mark Florisson committed
6718

Mark Florisson's avatar
Mark Florisson committed
6719 6720 6721
        # [NameNode]
        self.assigned_nodes = []

Mark Florisson's avatar
Mark Florisson committed
6722 6723 6724
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)

6725 6726
        self.num_threads = None

6727
        if self.kwargs:
6728 6729 6730
            # Try to find num_threads and chunksize keyword arguments
            pairs = []
            for dictitem in self.kwargs.key_value_pairs:
6731 6732
                if dictitem.key.value == 'num_threads':
                    self.num_threads = dictitem.value
6733 6734 6735 6736 6737 6738
                elif self.is_prange and dictitem.key.value == 'chunksize':
                    self.chunksize = dictitem.value
                else:
                    pairs.append(dictitem)

            self.kwargs.key_value_pairs = pairs
6739

6740 6741 6742 6743 6744
            try:
                self.kwargs = self.kwargs.compile_time_value(env)
            except Exception, e:
                error(self.kwargs.pos, "Only compile-time values may be "
                                       "supplied as keyword arguments")
6745 6746 6747 6748 6749 6750 6751 6752 6753
        else:
            self.kwargs = {}

        for kw, val in self.kwargs.iteritems():
            if kw not in self.valid_keyword_arguments:
                error(self.pos, "Invalid keyword argument: %s" % kw)
            else:
                setattr(self, kw, val)

6754
    def analyse_expressions(self, env):
6755 6756
        if self.num_threads:
            self.num_threads.analyse_expressions(env)
6757 6758 6759 6760

        if self.chunksize:
            self.chunksize.analyse_expressions(env)

6761
        self.body.analyse_expressions(env)
6762
        self.analyse_sharing_attributes(env)
6763

6764
        if self.num_threads is not None:
6765 6766
            if (self.parent and self.parent.num_threads is not None and not
                                                    self.parent.is_prange):
6767 6768
                error(self.pos,
                      "num_threads already declared in outer section")
6769
            elif self.parent and not self.parent.is_prange:
6770
                error(self.pos,
6771 6772 6773 6774
                      "num_threads must be declared in the parent parallel section")
            elif (self.num_threads.type.is_int and
                  self.num_threads.is_literal and
                  self.num_threads.compile_time_value(env) <= 0):
6775 6776 6777
                error(self.pos,
                      "argument to num_threads must be greater than 0")

Mark Florisson's avatar
Mark Florisson committed
6778 6779
            if not self.num_threads.is_simple():
                self.num_threads = self.num_threads.coerce_to(
6780
                                PyrexTypes.c_int_type, env).coerce_to_temp(env)
6781 6782

    def analyse_sharing_attributes(self, env):
Mark Florisson's avatar
Mark Florisson committed
6783
        """
6784 6785 6786
        Analyse the privates for this block and set them in self.privates.
        This should be called in a post-order fashion during the
        analyse_expressions phase
Mark Florisson's avatar
Mark Florisson committed
6787
        """
6788
        for entry, (pos, op) in self.assignments.iteritems():
Mark Florisson's avatar
Mark Florisson committed
6789

6790 6791 6792 6793 6794 6795
            if self.is_prange and not self.is_parallel:
                # closely nested prange in a with parallel block, disallow
                # assigning to privates in the with parallel block (we
                # consider it too implicit and magicky for users)
                if entry in self.parent.assignments:
                    error(pos,
Mark Florisson's avatar
Mark Florisson committed
6796
                          "Cannot assign to private of outer parallel block")
6797 6798 6799 6800 6801 6802 6803
                    continue

            if not self.is_prange and op:
                # Again possible, but considered to magicky
                error(pos, "Reductions not allowed for parallel blocks")
                continue

Mark Florisson's avatar
Mark Florisson committed
6804 6805 6806
            # By default all variables should have the same values as if
            # executed sequentially
            lastprivate = True
6807
            self.propagate_var_privatization(entry, pos, op, lastprivate)
6808

6809
    def propagate_var_privatization(self, entry, pos, op, lastprivate):
6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837
        """
        Propagate the sharing attributes of a variable. If the privatization is
        determined by a parent scope, done propagate further.

        If we are a prange, we propagate our sharing attributes outwards to
        other pranges. If we are a prange in parallel block and the parallel
        block does not determine the variable private, we propagate to the
        parent of the parent. Recursion stops at parallel blocks, as they have
        no concept of lastprivate or reduction.

        So the following cases propagate:

            sum is a reduction for all loops:

                for i in prange(n):
                    for j in prange(n):
                        for k in prange(n):
                            sum += i * j * k

            sum is a reduction for both loops, local_var is private to the
            parallel with block:

                for i in prange(n):
                    with parallel:
                        local_var = ... # private to the parallel
                        for j in prange(n):
                            sum += i * j

Mark Florisson's avatar
Mark Florisson committed
6838 6839
        Nested with parallel blocks are disallowed, because they wouldn't
        allow you to propagate lastprivates or reductions:
6840 6841 6842 6843

            #pragma omp parallel for lastprivate(i)
            for i in prange(n):

Mark Florisson's avatar
Mark Florisson committed
6844 6845
                sum = 0

6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861
                #pragma omp parallel private(j, sum)
                with parallel:

                    #pragma omp parallel
                    with parallel:

                        #pragma omp for lastprivate(j) reduction(+:sum)
                        for j in prange(n):
                            sum += i

                    # sum and j are well-defined here

                # sum and j are undefined here

            # sum and j are undefined here
        """
6862
        self.privates[entry] = (op, lastprivate)
6863 6864 6865 6866 6867

        if entry.type.is_memoryviewslice:
            error(pos, "Memoryview slices can only be shared in parallel sections")
            return

6868 6869 6870 6871 6872 6873
        if self.is_prange:
            if not self.is_parallel and entry not in self.parent.assignments:
                # Parent is a parallel with block
                parent = self.parent.parent
            else:
                parent = self.parent
Mark Florisson's avatar
Mark Florisson committed
6874

6875 6876 6877
            # We don't need to propagate privates, only reductions and
            # lastprivates
            if parent and (op or lastprivate):
6878
                parent.propagate_var_privatization(entry, pos, op, lastprivate)
Mark Florisson's avatar
Mark Florisson committed
6879 6880 6881 6882 6883 6884 6885 6886 6887

    def _allocate_closure_temp(self, code, entry):
        """
        Helper function that allocate a temporary for a closure variable that
        is assigned to.
        """
        if self.parent:
            return self.parent._allocate_closure_temp(code, entry)

6888 6889 6890
        if entry.cname in self.seen_closure_vars:
            return entry.cname

6891
        cname = code.funcstate.allocate_temp(entry.type, True)
6892 6893 6894 6895 6896 6897

        # Add both the actual cname and the temp cname, as the actual cname
        # will be replaced with the temp cname on the entry
        self.seen_closure_vars.add(entry.cname)
        self.seen_closure_vars.add(cname)

Mark Florisson's avatar
Mark Florisson committed
6898 6899 6900 6901
        self.modified_entries.append((entry, entry.cname))
        code.putln("%s = %s;" % (cname, entry.cname))
        entry.cname = cname

6902
    def initialize_privates_to_nan(self, code, exclude=None):
6903
        first = True
6904

6905
        for entry, (op, lastprivate) in self.privates.iteritems():
6906
            if not op and (not exclude or entry != exclude):
6907
                invalid_value = entry.type.invalid_value()
6908

6909
                if invalid_value:
6910 6911 6912 6913
                    if first:
                        code.putln("/* Initialize private variables to "
                                   "invalid values */")
                        code.globalstate.use_utility_code(
6914
                                invalid_values_utility_code)
6915 6916 6917
                        first = False

                    have_invalid_values = True
6918
                    code.putln("%s = %s;" % (entry.cname,
6919
                                             entry.type.cast_code(invalid_value)))
6920

6921
    def evaluate_before_block(self, code, expr):
Mark Florisson's avatar
Mark Florisson committed
6922
        c = self.begin_of_parallel_control_block_point_after_decls
6923 6924 6925 6926 6927 6928 6929 6930 6931 6932
        # we need to set the owner to ourselves temporarily, as
        # allocate_temp may generate a comment in the middle of our pragma
        # otherwise when DebugFlags.debug_temp_code_comments is in effect
        owner = c.funcstate.owner
        c.funcstate.owner = c
        expr.generate_evaluation_code(c)
        c.funcstate.owner = owner

        return expr.result()

6933 6934 6935 6936 6937
    def put_num_threads(self, code):
        """
        Write self.num_threads if set as the num_threads OpenMP directive
        """
        if self.num_threads is not None:
6938 6939
            code.put(" num_threads(%s)" % self.evaluate_before_block(code,
                                                        self.num_threads))
6940

6941

Mark Florisson's avatar
Mark Florisson committed
6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952
    def declare_closure_privates(self, code):
        """
        If a variable is in a scope object, we need to allocate a temp and
        assign the value from the temp to the variable in the scope object
        after the parallel section. This kind of copying should be done only
        in the outermost parallel section.
        """
        self.modified_entries = []

        for entry, (pos, op) in self.assignments.iteritems():
            if entry.from_closure or entry.in_closure:
6953
                self._allocate_closure_temp(code, entry)
Mark Florisson's avatar
Mark Florisson committed
6954 6955

    def release_closure_privates(self, code):
6956 6957 6958
        """
        Release any temps used for variables in scope objects. As this is the
        outermost parallel block, we don't need to delete the cnames from
6959
        self.seen_closure_vars.
6960
        """
Mark Florisson's avatar
Mark Florisson committed
6961 6962 6963 6964 6965
        for entry, original_cname in self.modified_entries:
            code.putln("%s = %s;" % (original_cname, entry.cname))
            code.funcstate.release_temp(entry.cname)
            entry.cname = original_cname

6966 6967 6968 6969 6970 6971
    def privatize_temps(self, code, exclude_temps=()):
        """
        Make any used temporaries private. Before the relevant code block
        code.start_collecting_temps() should have been called.
        """
        if self.is_parallel:
6972
            c = self.privatization_insertion_point
6973

6974
            self.temps = temps = code.funcstate.stop_collecting_temps()
6975 6976
            privates, firstprivates = [], []
            for temp, type in temps:
6977
                if type.is_pyobject or type.is_memoryviewslice:
6978 6979 6980
                    firstprivates.append(temp)
                else:
                    privates.append(temp)
6981

6982 6983 6984 6985
            if privates:
                c.put(" private(%s)" % ", ".join(privates))
            if firstprivates:
                c.put(" firstprivate(%s)" % ", ".join(firstprivates))
6986 6987 6988 6989 6990 6991 6992 6993

            if self.breaking_label_used:
                shared_vars = [Naming.parallel_why]
                if self.error_label_used:
                    shared_vars.extend(self.parallel_exc)
                    c.put(" private(%s, %s, %s)" % self.pos_info)

                c.put(" shared(%s)" % ', '.join(shared_vars))
6994

6995 6996 6997 6998 6999 7000 7001 7002 7003 7004
    def cleanup_temps(self, code):
        # Now clean up any memoryview slice and object temporaries
        if self.is_parallel and not self.is_nested_prange:
            code.putln("/* Clean up any temporaries */")
            for temp, type in self.temps:
                if type.is_memoryviewslice:
                    code.put_xdecref_memoryviewslice(temp, have_gil=False)
                elif type.is_pyobject:
                    code.put_xdecref(temp, type)
                    code.putln("%s = NULL;" % temp)
7005

7006
    def setup_parallel_control_flow_block(self, code):
7007
        """
7008 7009
        Sets up a block that surrounds the parallel block to determine
        how the parallel section was exited. Any kind of return is
7010 7011 7012
        trapped (break, continue, return, exceptions). This is the idea:

        {
7013
            int why = 0;
7014 7015 7016 7017 7018 7019 7020

            #pragma omp parallel
            {
                return # -> goto new_return_label;
                goto end_parallel;

            new_return_label:
7021
                why = 3;
7022
                goto end_parallel;
7023

7024
            end_parallel:;
7025
                #pragma omp flush(why) # we need to flush for every iteration
7026 7027
            }

7028
            if (why == 3)
7029 7030 7031 7032 7033 7034 7035 7036
                goto old_return_label;
        }
        """
        self.old_loop_labels = code.new_loop_labels()
        self.old_error_label = code.new_error_label()
        self.old_return_label = code.return_label
        code.return_label = code.new_label(name="return")

7037 7038
        code.begin_block() # parallel control flow block
        self.begin_of_parallel_control_block_point = code.insertion_point()
Mark Florisson's avatar
Mark Florisson committed
7039
        self.begin_of_parallel_control_block_point_after_decls = code.insertion_point()
7040

7041 7042
        self.undef_builtin_expect_apple_gcc_bug(code)

7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054
    def begin_parallel_block(self, code):
        """
        Each OpenMP thread in a parallel section that contains a with gil block
        must have the thread-state initialized. The call to
        PyGILState_Release() then deallocates our threadstate. If we wouldn't
        do this, each with gil block would allocate and deallocate one, thereby
        losing exception information before it can be saved before leaving the
        parallel section.
        """
        self.begin_of_parallel_block = code.insertion_point()

    def end_parallel_block(self, code):
7055 7056 7057 7058 7059 7060 7061 7062 7063
        """
        To ensure all OpenMP threads have thread states, we ensure the GIL
        in each thread (which creates a thread state if it doesn't exist),
        after which we release the GIL.
        On exit, reacquire the GIL and release the thread state.

        If compiled without OpenMP support (at the C level), then we still have
        to acquire the GIL to decref any object temporaries.
        """
7064 7065 7066 7067
        if self.error_label_used:
            begin_code = self.begin_of_parallel_block
            end_code = code

7068
            begin_code.putln("#ifdef _OPENMP")
7069 7070
            begin_code.put_ensure_gil(declare_gilstate=True)
            begin_code.putln("Py_BEGIN_ALLOW_THREADS")
7071
            begin_code.putln("#endif /* _OPENMP */")
7072

7073
            end_code.putln("#ifdef _OPENMP")
7074
            end_code.putln("Py_END_ALLOW_THREADS")
7075 7076 7077 7078 7079
            end_code.putln("#else")
            end_code.put_safe("{\n")
            end_code.put_ensure_gil()
            end_code.putln("#endif /* _OPENMP */")
            self.cleanup_temps(end_code)
7080
            end_code.put_release_ensured_gil()
7081 7082
            end_code.putln("#ifndef _OPENMP")
            end_code.put_safe("}\n")
7083
            end_code.putln("#endif /* _OPENMP */")
7084

7085 7086 7087 7088
    def trap_parallel_exit(self, code, should_flush=False):
        """
        Trap any kind of return inside a parallel construct. 'should_flush'
        indicates whether the variable should be flushed, which is needed by
7089 7090 7091 7092 7093 7094 7095 7096 7097
        prange to skip the loop. It also indicates whether we need to register
        a continue (we need this for parallel blocks, but not for prange
        loops, as it is a direct jump there).

        It uses the same mechanism as try/finally:
            1 continue
            2 break
            3 return
            4 error
7098
        """
7099
        save_lastprivates_label = code.new_label()
7100
        dont_return_label = code.new_label()
7101 7102 7103 7104
        insertion_point = code.insertion_point()

        self.any_label_used = False
        self.breaking_label_used = False
7105
        self.error_label_used = False
7106

7107 7108 7109 7110 7111 7112
        self.parallel_private_temps = []

        all_labels = code.get_all_labels()

        # Figure this out before starting to generate any code
        for label in all_labels:
7113 7114
            if code.label_used(label):
                self.breaking_label_used = (self.breaking_label_used or
7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125
                                            label != code.continue_label)
                self.any_label_used = True

        if self.any_label_used:
            code.put_goto(dont_return_label)

        for i, label in enumerate(all_labels):
            if not code.label_used(label):
                continue

            is_continue_label = label == code.continue_label
7126

7127
            code.put_label(label)
7128

7129 7130 7131 7132
            if not (should_flush and is_continue_label):
                if label == code.error_label:
                    self.error_label_used = True
                    self.fetch_parallel_exception(code)
7133

7134
                code.putln("%s = %d;" % (Naming.parallel_why, i + 1))
7135

7136 7137 7138 7139
            if (self.breaking_label_used and self.is_prange and not
                    is_continue_label):
                code.put_goto(save_lastprivates_label)
            else:
7140 7141
                code.put_goto(dont_return_label)

7142
        if self.any_label_used:
7143 7144 7145 7146 7147
            if self.is_prange and self.breaking_label_used:
                # Don't rely on lastprivate, save our lastprivates
                code.put_label(save_lastprivates_label)
                self.save_parallel_vars(code)

7148 7149 7150
            code.put_label(dont_return_label)

            if should_flush and self.breaking_label_used:
7151 7152
                code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_why)

7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181
    def save_parallel_vars(self, code):
        """
        The following shenanigans are instated when we break, return or
        propagate errors from a prange. In this case we cannot rely on
        lastprivate() to do its job, as no iterations may have executed yet
        in the last thread, leaving the values undefined. It is most likely
        that the breaking thread has well-defined values of the lastprivate
        variables, so we keep those values.
        """
        section_name = ("__pyx_parallel_lastprivates%d" %
                                            self.critical_section_counter)
        code.putln_openmp("#pragma omp critical(%s)" % section_name)
        ParallelStatNode.critical_section_counter += 1

        code.begin_block() # begin critical section

        c = self.begin_of_parallel_control_block_point

        temp_count = 0
        for entry, (op, lastprivate) in self.privates.iteritems():
            if not lastprivate or entry.type.is_pyobject:
                continue

            type_decl = entry.type.declaration_code("")
            temp_cname = "__pyx_parallel_temp%d" % temp_count
            private_cname = entry.cname

            temp_count += 1

7182 7183 7184 7185 7186
            invalid_value = entry.type.invalid_value()
            if invalid_value:
                init = ' = ' + invalid_value
            else:
                init = ''
7187
            # Declare the parallel private in the outer block
7188
            c.putln("%s %s%s;" % (type_decl, temp_cname, init))
7189 7190 7191 7192 7193 7194 7195 7196

            # Initialize before escaping
            code.putln("%s = %s;" % (temp_cname, private_cname))

            self.parallel_private_temps.append((temp_cname, private_cname))

        code.end_block() # end critical section

7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253
    def fetch_parallel_exception(self, code):
        """
        As each OpenMP thread may raise an exception, we need to fetch that
        exception from the threadstate and save it for after the parallel
        section where it can be re-raised in the master thread.

        Although it would seem that __pyx_filename, __pyx_lineno and
        __pyx_clineno are only assigned to under exception conditions (i.e.,
        when we have the GIL), and thus should be allowed to be shared without
        any race condition, they are in fact subject to the same race
        conditions that they were previously when they were global variables
        and functions were allowed to release the GIL:

            thread A                thread B
                acquire
                set lineno
                release
                                        acquire
                                        set lineno
                                        release
                acquire
                fetch exception
                release
                                        skip the fetch

                deallocate threadstate  deallocate threadstate
        """
        code.begin_block()
        code.put_ensure_gil(declare_gilstate=True)

        code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_exc_type)
        code.putln(
            "if (!%s) {" % Naming.parallel_exc_type)

        code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % self.parallel_exc)
        pos_info = chain(*zip(self.parallel_pos_info, self.pos_info))
        code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
        code.putln('__Pyx_GOTREF(%s);' % Naming.parallel_exc_type)

        code.putln(
            "}")

        code.put_release_ensured_gil()
        code.end_block()

    def restore_parallel_exception(self, code):
        "Re-raise a parallel exception"
        code.begin_block()
        code.put_ensure_gil(declare_gilstate=True)

        code.putln("__Pyx_ErrRestore(%s, %s, %s);" % self.parallel_exc)
        pos_info = chain(*zip(self.pos_info, self.parallel_pos_info))
        code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info))
        code.putln("__Pyx_GIVEREF(%s);" % Naming.parallel_exc_type)

        code.put_release_ensured_gil()
        code.end_block()
7254 7255

    def restore_labels(self, code):
7256 7257 7258 7259 7260 7261
        """
        Restore all old labels. Call this before the 'else' clause to for
        loops and always before ending the parallel control flow block.
        """
        code.set_all_labels(self.old_loop_labels + (self.old_return_label,
                                                    self.old_error_label))
7262

7263 7264 7265 7266 7267 7268 7269
    def end_parallel_control_flow_block(self, code,
                                        break_=False, continue_=False):
        """
        This ends the parallel control flow block and based on how the parallel
        section was exited, takes the corresponding action. The break_ and
        continue_ parameters indicate whether these should be propagated
        outwards:
7270

7271 7272 7273 7274 7275 7276 7277
            for i in prange(...):
                with cython.parallel.parallel():
                    continue

        Here break should be trapped in the parallel block, and propagated to
        the for loop.
        """
7278 7279 7280 7281
        c = self.begin_of_parallel_control_block_point

        # Firstly, always prefer errors over returning, continue or break
        if self.error_label_used:
Mark Florisson's avatar
Mark Florisson committed
7282 7283
            c.putln("const char *%s = NULL; int %s = 0, %s = 0;" %
                                                self.parallel_pos_info)
7284

7285
            c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" %
Mark Florisson's avatar
Mark Florisson committed
7286
                                                        self.parallel_exc)
7287 7288 7289 7290 7291 7292 7293 7294 7295

            code.putln(
                "if (%s) {" % Naming.parallel_exc_type)
            code.putln("/* This may have been overridden by a continue, "
                       "break or return in another thread. Prefer the error. */")
            code.putln("%s = 4;" % Naming.parallel_why)
            code.putln(
                "}")

7296 7297 7298 7299 7300 7301 7302
        if continue_:
            any_label_used = self.any_label_used
        else:
            any_label_used = self.breaking_label_used

        if any_label_used:
            # __pyx_parallel_why is used, declare and initialize
7303 7304
            c.putln("int %s;" % Naming.parallel_why)
            c.putln("%s = 0;" % Naming.parallel_why)
7305

7306 7307 7308 7309 7310 7311
            code.putln(
                "if (%s) {" % Naming.parallel_why)

            for temp_cname, private_cname in self.parallel_private_temps:
                code.putln("%s = %s;" % (private_cname, temp_cname))

7312
            code.putln("switch (%s) {" % Naming.parallel_why)
7313 7314 7315 7316 7317 7318 7319 7320 7321 7322
            if continue_:
                code.put("    case 1: ")
                code.put_goto(code.continue_label)

            if break_:
                code.put("    case 2: ")
                code.put_goto(code.break_label)

            code.put("    case 3: ")
            code.put_goto(code.return_label)
7323 7324

            if self.error_label_used:
7325
                code.globalstate.use_utility_code(restore_exception_utility_code)
7326 7327 7328
                code.putln("    case 4:")
                self.restore_parallel_exception(code)
                code.put_goto(code.error_label)
7329

7330 7331 7332
            code.putln("}") # end switch
            code.putln(
                "}") # end if
7333 7334

        code.end_block() # end parallel control flow block
7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346
        self.redef_builtin_expect_apple_gcc_bug(code)

    # FIXME: improve with version number for OS X Lion
    buggy_platform_macro_condition = "(defined(__APPLE__) || defined(__OSX__))"
    have_expect_condition = "(defined(__GNUC__) && " \
                             "(__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))"
    redef_condition = "(%s && %s)" % (buggy_platform_macro_condition, have_expect_condition)

    def undef_builtin_expect_apple_gcc_bug(self, code):
        """
        A bug on OS X Lion disallows __builtin_expect macros. This code avoids them
        """
7347
        if not self.parent:
7348
            code.undef_builtin_expect(self.redef_condition)
7349 7350

    def redef_builtin_expect_apple_gcc_bug(self, code):
7351
        if not self.parent:
7352
            code.redef_builtin_expect(self.redef_condition)
7353

Mark Florisson's avatar
Mark Florisson committed
7354 7355 7356

class ParallelWithBlockNode(ParallelStatNode):
    """
7357
    This node represents a 'with cython.parallel.parallel():' block
Mark Florisson's avatar
Mark Florisson committed
7358 7359
    """

7360 7361 7362 7363 7364 7365 7366 7367 7368
    valid_keyword_arguments = ['num_threads']

    num_threads = None

    def analyse_declarations(self, env):
        super(ParallelWithBlockNode, self).analyse_declarations(env)
        if self.args:
            error(self.pos, "cython.parallel.parallel() does not take "
                            "positional arguments")
7369

Mark Florisson's avatar
Mark Florisson committed
7370 7371
    def generate_execution_code(self, code):
        self.declare_closure_privates(code)
7372
        self.setup_parallel_control_flow_block(code)
Mark Florisson's avatar
Mark Florisson committed
7373 7374 7375

        code.putln("#ifdef _OPENMP")
        code.put("#pragma omp parallel ")
7376 7377

        if self.privates:
7378 7379
            privates = [e.cname for e in self.privates
                                    if not e.type.is_pyobject]
7380
            code.put('private(%s)' % ', '.join(privates))
7381

7382
        self.privatization_insertion_point = code.insertion_point()
7383
        self.put_num_threads(code)
7384
        code.putln("")
7385

7386 7387
        code.putln("#endif /* _OPENMP */")

7388
        code.begin_block() # parallel block
7389
        self.begin_parallel_block(code)
7390
        self.initialize_privates_to_nan(code)
7391
        code.funcstate.start_collecting_temps()
Mark Florisson's avatar
Mark Florisson committed
7392
        self.body.generate_execution_code(code)
7393
        self.trap_parallel_exit(code)
7394
        self.privatize_temps(code)
7395 7396
        self.end_parallel_block(code)
        code.end_block() # end parallel block
7397

7398 7399
        continue_ = code.label_used(code.continue_label)
        break_ = code.label_used(code.break_label)
Mark Florisson's avatar
Mark Florisson committed
7400

7401 7402 7403
        self.restore_labels(code)
        self.end_parallel_control_flow_block(code, break_=break_,
                                             continue_=continue_)
Mark Florisson's avatar
Mark Florisson committed
7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414
        self.release_closure_privates(code)


class ParallelRangeNode(ParallelStatNode):
    """
    This node represents a 'for i in cython.parallel.prange():' construct.

    target       NameNode       the target iteration variable
    else_clause  Node or None   the else clause of this loop
    """

7415 7416
    child_attrs = ['body', 'target', 'else_clause', 'args', 'num_threads',
                   'chunksize']
Mark Florisson's avatar
Mark Florisson committed
7417 7418 7419 7420 7421 7422

    body = target = else_clause = args = None

    start = stop = step = None

    is_prange = True
7423

7424
    nogil = None
7425 7426
    schedule = None

7427
    valid_keyword_arguments = ['schedule', 'nogil', 'num_threads', 'chunksize']
Mark Florisson's avatar
Mark Florisson committed
7428

7429 7430 7431 7432 7433
    def __init__(self, pos, **kwds):
        super(ParallelRangeNode, self).__init__(pos, **kwds)
        # Pretend to be a ForInStatNode for control flow analysis
        self.iterator = PassStatNode(pos)

Mark Florisson's avatar
Mark Florisson committed
7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450
    def analyse_declarations(self, env):
        super(ParallelRangeNode, self).analyse_declarations(env)
        self.target.analyse_target_declaration(env)
        if self.else_clause is not None:
            self.else_clause.analyse_declarations(env)

        if not self.args or len(self.args) > 3:
            error(self.pos, "Invalid number of positional arguments to prange")
            return

        if len(self.args) == 1:
            self.stop, = self.args
        elif len(self.args) == 2:
            self.start, self.stop = self.args
        else:
            self.start, self.stop, self.step = self.args

Mark Florisson's avatar
Mark Florisson committed
7451 7452 7453
        if hasattr(self.schedule, 'decode'):
            self.schedule = self.schedule.decode('ascii')

Mark Florisson's avatar
Mark Florisson committed
7454 7455
        if self.schedule not in (None, 'static', 'dynamic', 'guided',
                                 'runtime'):
Mark Florisson's avatar
Mark Florisson committed
7456
            error(self.pos, "Invalid schedule argument to prange: %s" %
Mark Florisson's avatar
Mark Florisson committed
7457 7458 7459
                                                        (self.schedule,))

    def analyse_expressions(self, env):
7460 7461 7462 7463
        if self.nogil:
            was_nogil = env.nogil
            env.nogil = True

7464 7465 7466
        if self.target is None:
            error(self.pos, "prange() can only be used as part of a for loop")
            return
Mark Florisson's avatar
Mark Florisson committed
7467

7468
        self.target.analyse_target_types(env)
Mark Florisson's avatar
Mark Florisson committed
7469

7470 7471 7472 7473 7474 7475 7476 7477
        if not self.target.type.is_numeric:
            # Not a valid type, assume one for now anyway

            if not self.target.type.is_pyobject:
                # nogil_check will catch the is_pyobject case
                error(self.target.pos,
                      "Must be of numeric type, not %s" % self.target.type)

7478
            self.index_type = PyrexTypes.c_py_ssize_t_type
7479 7480
        else:
            self.index_type = self.target.type
7481 7482 7483 7484
            if not self.index_type.signed:
                warning(self.target.pos,
                        "Unsigned index type not allowed before OpenMP 3.0",
                        level=2)
Mark Florisson's avatar
Mark Florisson committed
7485 7486 7487 7488 7489 7490 7491 7492 7493

        # Setup start, stop and step, allocating temps if needed
        self.names = 'start', 'stop', 'step'
        start_stop_step = self.start, self.stop, self.step

        for node, name in zip(start_stop_step, self.names):
            if node is not None:
                node.analyse_types(env)
                if not node.type.is_numeric:
7494 7495
                    error(node.pos, "%s argument must be numeric" % name)
                    continue
Mark Florisson's avatar
Mark Florisson committed
7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508

                if not node.is_literal:
                    node = node.coerce_to_temp(env)
                    setattr(self, name, node)

                # As we range from 0 to nsteps, computing the index along the
                # way, we need a fitting type for 'i' and 'nsteps'
                self.index_type = PyrexTypes.widest_numeric_type(
                                        self.index_type, node.type)

        if self.else_clause is not None:
            self.else_clause.analyse_expressions(env)

7509 7510 7511 7512 7513 7514 7515 7516
        # Although not actually an assignment in this scope, it should be
        # treated as such to ensure it is unpacked if a closure temp, and to
        # ensure lastprivate behaviour and propagation. If the target index is
        # not a NameNode, it won't have an entry, and an error was issued by
        # ParallelRangeTransform
        if hasattr(self.target, 'entry'):
            self.assignments[self.target.entry] = self.target.pos, None

7517
        super(ParallelRangeNode, self).analyse_expressions(env)
7518

7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533
        if self.chunksize:
            if not self.schedule:
                error(self.chunksize.pos,
                      "Must provide schedule with chunksize")
            elif self.schedule == 'runtime':
                error(self.chunksize.pos,
                      "Chunksize not valid for the schedule runtime")
            elif (self.chunksize.type.is_int and
                  self.chunksize.is_literal and
                  self.chunksize.compile_time_value(env) <= 0):
                error(self.chunksize.pos, "Chunksize must not be negative")

            self.chunksize = self.chunksize.coerce_to(
                            PyrexTypes.c_int_type, env).coerce_to_temp(env)

7534 7535 7536
        if self.nogil:
            env.nogil = was_nogil

7537 7538 7539 7540 7541 7542 7543 7544 7545 7546
        self.is_nested_prange = self.parent and self.parent.is_prange
        if self.is_nested_prange:
            parent = self
            while parent.parent and parent.parent.is_prange:
                parent = parent.parent

            parent.assignments.update(self.assignments)
            parent.privates.update(self.privates)
            parent.assigned_nodes.extend(self.assigned_nodes)

Mark Florisson's avatar
Mark Florisson committed
7547 7548
    def nogil_check(self, env):
        names = 'start', 'stop', 'step', 'target'
7549
        nodes = self.start, self.stop, self.step, self.target
Mark Florisson's avatar
Mark Florisson committed
7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594
        for name, node in zip(names, nodes):
            if node is not None and node.type.is_pyobject:
                error(node.pos, "%s may not be a Python object "
                                "as we don't have the GIL" % name)

    def generate_execution_code(self, code):
        """
        Generate code in the following steps

            1)  copy any closure variables determined thread-private
                into temporaries

            2)  allocate temps for start, stop and step

            3)  generate a loop that calculates the total number of steps,
                which then computes the target iteration variable for every step:

                    for i in prange(start, stop, step):
                        ...

                becomes

                    nsteps = (stop - start) / step;
                    i = start;

                    #pragma omp parallel for lastprivate(i)
                    for (temp = 0; temp < nsteps; temp++) {
                        i = start + step * temp;
                        ...
                    }

                Note that accumulation of 'i' would have a data dependency
                between iterations.

                Also, you can't do this

                    for (i = start; i < stop; i += step)
                        ...

                as the '<' operator should become '>' for descending loops.
                'for i from x < i < y:' does not suffer from this problem
                as the relational operator is known at compile time!

            4) release our temps and write back any private closure variables
        """
7595
        self.declare_closure_privates(code)
Mark Florisson's avatar
Mark Florisson committed
7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626

        # This can only be a NameNode
        target_index_cname = self.target.entry.cname

        # This will be used as the dict to format our code strings, holding
        # the start, stop , step, temps and target cnames
        fmt_dict = {
            'target': target_index_cname,
        }

        # Setup start, stop and step, allocating temps if needed
        start_stop_step = self.start, self.stop, self.step
        defaults = '0', '0', '1'
        for node, name, default in zip(start_stop_step, self.names, defaults):
            if node is None:
                result = default
            elif node.is_literal:
                result = node.get_constant_c_result_code()
            else:
                node.generate_evaluation_code(code)
                result = node.result()

            fmt_dict[name] = result

        fmt_dict['i'] = code.funcstate.allocate_temp(self.index_type, False)
        fmt_dict['nsteps'] = code.funcstate.allocate_temp(self.index_type, False)

        # TODO: check if the step is 0 and if so, raise an exception in a
        # 'with gil' block. For now, just abort
        code.putln("if (%(step)s == 0) abort();" % fmt_dict)

7627
        self.setup_parallel_control_flow_block(code) # parallel control flow block
7628

7629
        self.control_flow_var_code_point = code.insertion_point()
7630

7631
        # Note: nsteps is private in an outer scope if present
Mark Florisson's avatar
Mark Florisson committed
7632 7633
        code.putln("%(nsteps)s = (%(stop)s - %(start)s) / %(step)s;" % fmt_dict)

7634 7635 7636 7637 7638 7639 7640
        # The target iteration variable might not be initialized, do it only if
        # we are executing at least 1 iteration, otherwise we should leave the
        # target unaffected. The target iteration variable is firstprivate to
        # shut up compiler warnings caused by lastprivate, as the compiler
        # erroneously believes that nsteps may be <= 0, leaving the private
        # target index uninitialized
        code.putln("if (%(nsteps)s > 0)" % fmt_dict)
7641
        code.begin_block() # if block
Mark Florisson's avatar
Mark Florisson committed
7642
        self.generate_loop(code, fmt_dict)
7643
        code.end_block() # end if block
Mark Florisson's avatar
Mark Florisson committed
7644

7645 7646 7647
        self.restore_labels(code)

        if self.else_clause:
7648
            if self.breaking_label_used:
7649
                code.put("if (%s < 2)" % Naming.parallel_why)
7650 7651 7652 7653 7654 7655 7656

            code.begin_block() # else block
            code.putln("/* else */")
            self.else_clause.generate_execution_code(code)
            code.end_block() # end else block

        # ------ cleanup ------
7657
        self.end_parallel_control_flow_block(code) # end parallel control flow block
7658

Mark Florisson's avatar
Mark Florisson committed
7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671
        # And finally, release our privates and write back any closure
        # variables
        for temp in start_stop_step:
            if temp is not None:
                temp.generate_disposal_code(code)
                temp.free_temps(code)

        code.funcstate.release_temp(fmt_dict['i'])
        code.funcstate.release_temp(fmt_dict['nsteps'])

        self.release_closure_privates(code)

    def generate_loop(self, code, fmt_dict):
7672 7673 7674 7675
        if self.is_nested_prange:
            code.putln("#if 0")
        else:
            code.putln("#ifdef _OPENMP")
Mark Florisson's avatar
Mark Florisson committed
7676 7677 7678

        if not self.is_parallel:
            code.put("#pragma omp for")
7679
            self.privatization_insertion_point = code.insertion_point()
7680
            reduction_codepoint = self.parent.privatization_insertion_point
Mark Florisson's avatar
Mark Florisson committed
7681
        else:
7682 7683
            code.put("#pragma omp parallel")
            self.privatization_insertion_point = code.insertion_point()
7684
            reduction_codepoint = self.privatization_insertion_point
7685 7686 7687 7688 7689 7690 7691 7692
            code.putln("")
            code.putln("#endif /* _OPENMP */")

            code.begin_block() # pragma omp parallel begin block

            # Initialize the GIL if needed for this thread
            self.begin_parallel_block(code)

7693 7694 7695 7696
            if self.is_nested_prange:
                code.putln("#if 0")
            else:
                code.putln("#ifdef _OPENMP")
7697
            code.put("#pragma omp for")
Mark Florisson's avatar
Mark Florisson committed
7698

7699
        for entry, (op, lastprivate) in self.privates.iteritems():
Mark Florisson's avatar
Mark Florisson committed
7700
            # Don't declare the index variable as a reduction
7701
            if op and op in "+*-&^|" and entry != self.target.entry:
7702 7703 7704
                if entry.type.is_pyobject:
                    error(self.pos, "Python objects cannot be reductions")
                else:
7705 7706 7707 7708
                    #code.put(" reduction(%s:%s)" % (op, entry.cname))
                    # This is the only way reductions + nesting works in gcc4.5
                    reduction_codepoint.put(
                                " reduction(%s:%s)" % (op, entry.cname))
7709
            else:
7710 7711
                if entry == self.target.entry:
                    code.put(" firstprivate(%s)" % entry.cname)
7712 7713
                    code.put(" lastprivate(%s)" % entry.cname)
                    continue
Mark Florisson's avatar
Mark Florisson committed
7714

7715
                if not entry.type.is_pyobject:
7716 7717 7718 7719
                    if lastprivate:
                        private = 'lastprivate'
                    else:
                        private = 'private'
Mark Florisson's avatar
Mark Florisson committed
7720

7721
                    code.put(" %s(%s)" % (private, entry.cname))
7722

Mark Florisson's avatar
Mark Florisson committed
7723
        if self.schedule:
7724 7725 7726 7727 7728 7729 7730
            if self.chunksize:
                chunksize = ", %s" % self.evaluate_before_block(code,
                                                                self.chunksize)
            else:
                chunksize = ""

            code.put(" schedule(%s%s)" % (self.schedule, chunksize))
7731

7732
        self.put_num_threads(reduction_codepoint)
7733

7734 7735
        code.putln("")
        code.putln("#endif /* _OPENMP */")
Mark Florisson's avatar
Mark Florisson committed
7736 7737

        code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict)
7738
        code.begin_block() # for loop block
7739

7740
        guard_around_body_codepoint = code.insertion_point()
7741

7742 7743
        # Start if guard block around the body. This may be unnecessary, but
        # at least it doesn't spoil indentation
Mark Florisson's avatar
Mark Florisson committed
7744
        code.begin_block()
7745

7746
        code.putln("%(target)s = %(start)s + %(step)s * %(i)s;" % fmt_dict)
7747 7748
        self.initialize_privates_to_nan(code, exclude=self.target.entry)

7749 7750 7751
        if self.is_parallel:
            code.funcstate.start_collecting_temps()

Mark Florisson's avatar
Mark Florisson committed
7752
        self.body.generate_execution_code(code)
7753
        self.trap_parallel_exit(code, should_flush=True)
7754 7755
        self.privatize_temps(code)

7756 7757 7758
        if self.breaking_label_used:
            # Put a guard around the loop body in case return, break or
            # exceptions might be used
7759
            guard_around_body_codepoint.putln("if (%s < 2)" % Naming.parallel_why)
7760

7761
        code.end_block() # end guard around loop body
7762
        code.end_block() # end for loop block
Mark Florisson's avatar
Mark Florisson committed
7763

7764 7765 7766 7767 7768
        if self.is_parallel:
            # Release the GIL and deallocate the thread state
            self.end_parallel_block(code)
            code.end_block() # pragma omp parallel end block

7769

7770 7771 7772 7773 7774 7775 7776 7777
class CnameDecoratorNode(StatNode):
    """
    This node is for the cname decorator in CythonUtilityCode:

        @cname('the_cname')
        cdef func(...):
            ...

7778 7779
    In case of a cdef class the cname specifies the objstruct_cname.

7780 7781 7782 7783 7784 7785 7786 7787
    node        the node to which the cname decorator is applied
    cname       the cname the node should get
    """

    child_attrs = ['node']

    def analyse_declarations(self, env):
        self.node.analyse_declarations(env)
7788 7789

        self.is_function = isinstance(self.node, FuncDefNode)
7790 7791
        is_struct_or_enum = isinstance(self.node, (CStructOrUnionDefNode,
                                                   CEnumDefNode))
7792 7793 7794 7795 7796
        e = self.node.entry

        if self.is_function:
            e.cname = self.cname
            e.func_cname = self.cname
7797
            e.used = True
7798 7799
            if e.pyfunc_cname and '.' in e.pyfunc_cname:
                e.pyfunc_cname = self.mangle(e.pyfunc_cname)
7800 7801
        elif is_struct_or_enum:
            e.cname = e.type.cname = self.cname
7802 7803 7804 7805
        else:
            scope = self.node.scope

            e.cname = self.cname
7806
            e.type.objstruct_cname = self.cname + '_obj'
7807
            e.type.typeobj_cname = Naming.typeobj_prefix + self.cname
7808
            e.type.typeptr_cname = self.cname + '_type'
7809
            e.type.scope.namespace_cname = e.type.typeptr_cname
7810 7811 7812 7813 7814 7815 7816

            e.as_variable.cname = py_object_type.cast_code(e.type.typeptr_cname)

            scope.scope_prefix = self.cname + "_"

            for name, entry in scope.entries.iteritems():
                if entry.func_cname:
7817 7818 7819 7820 7821 7822 7823 7824 7825 7826
                    entry.func_cname = self.mangle(entry.cname)
                if entry.pyfunc_cname:
                    old = entry.pyfunc_cname
                    entry.pyfunc_cname = self.mangle(entry.pyfunc_cname)

    def mangle(self, cname):
        if '.' in cname:
            # remove __pyx_base from func_cname
            cname = cname.split('.')[-1]
        return '%s_%s' % (self.cname, cname)
7827 7828 7829 7830 7831

    def analyse_expressions(self, env):
        self.node.analyse_expressions(env)

    def generate_function_definitions(self, env, code):
7832
        "Ensure a prototype for every @cname method in the right place"
7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857
        if self.is_function and env.is_c_class_scope:
            # method in cdef class, generate a prototype in the header
            h_code = code.globalstate['utility_code_proto']

            if isinstance(self.node, DefNode):
                self.node.generate_function_header(
                            h_code, with_pymethdef=False, proto_only=True)
            else:
                import ModuleNode
                entry = self.node.entry
                cname = entry.cname
                entry.cname = entry.func_cname

                ModuleNode.generate_cfunction_declaration(
                        entry,
                        env.global_scope(),
                        h_code,
                        definition=True)

                entry.cname = cname

        self.node.generate_function_definitions(env, code)

    def generate_execution_code(self, code):
        self.node.generate_execution_code(code)
Mark Florisson's avatar
Mark Florisson committed
7858

7859

William Stein's avatar
William Stein committed
7860 7861 7862 7863 7864 7865 7866 7867
#------------------------------------------------------------------------------------
#
#  Runtime support code
#
#------------------------------------------------------------------------------------

utility_function_predeclarations = \
"""
7868
/* inline attribute */
7869
#ifndef CYTHON_INLINE
7870
  #if defined(__GNUC__)
7871
    #define CYTHON_INLINE __inline__
7872
  #elif defined(_MSC_VER)
7873
    #define CYTHON_INLINE __inline
Robert Bradshaw's avatar
Robert Bradshaw committed
7874 7875
  #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
    #define CYTHON_INLINE inline
7876
  #else
7877
    #define CYTHON_INLINE
7878
  #endif
7879 7880
#endif

7881 7882 7883 7884
/* unused attribute */
#ifndef CYTHON_UNUSED
# if defined(__GNUC__)
#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
7885
#     define CYTHON_UNUSED __attribute__ ((__unused__))
7886 7887 7888
#   else
#     define CYTHON_UNUSED
#   endif
7889
# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
7890
#   define CYTHON_UNUSED __attribute__ ((__unused__))
7891
# else
7892
#   define CYTHON_UNUSED
7893 7894 7895
# endif
#endif

7896
typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/
7897

Robert Bradshaw's avatar
Robert Bradshaw committed
7898
"""
Robert Bradshaw's avatar
Robert Bradshaw committed
7899 7900 7901 7902

if Options.gcc_branch_hints:
    branch_prediction_macros = \
    """
7903
#ifdef __GNUC__
7904 7905 7906 7907 7908 7909 7910 7911
  /* Test for GCC > 2.95 */
  #if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
    #define likely(x)   __builtin_expect(!!(x), 1)
    #define unlikely(x) __builtin_expect(!!(x), 0)
  #else /* __GNUC__ > 2 ... */
    #define likely(x)   (x)
    #define unlikely(x) (x)
  #endif /* __GNUC__ > 2 ... */
7912
#else /* __GNUC__ */
7913 7914
  #define likely(x)   (x)
  #define unlikely(x) (x)
7915
#endif /* __GNUC__ */
Robert Bradshaw's avatar
Robert Bradshaw committed
7916 7917 7918 7919 7920 7921 7922
    """
else:
    branch_prediction_macros = \
    """
#define likely(x)   (x)
#define unlikely(x) (x)
    """
William Stein's avatar
William Stein committed
7923

7924 7925
#get_name_predeclaration = \
#"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/"
William Stein's avatar
William Stein committed
7926

7927 7928
#get_name_interned_predeclaration = \
#"static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/"
William Stein's avatar
William Stein committed
7929 7930 7931

#------------------------------------------------------------------------------------

7932 7933
printing_utility_code = UtilityCode.load_cached("Print", "Printing.c")
printing_one_utility_code = UtilityCode.load_cached("PrintOne", "Printing.c")
7934 7935


William Stein's avatar
William Stein committed
7936 7937
#------------------------------------------------------------------------------------

7938 7939 7940 7941 7942 7943 7944
# Exception raising code
#
# Exceptions are raised by __Pyx_Raise() and stored as plain
# type/value/tb in PyThreadState->curexc_*.  When being caught by an
# 'except' statement, curexc_* is moved over to exc_* by
# __Pyx_GetException()

7945 7946 7947 7948 7949 7950
restore_exception_utility_code = UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")
raise_utility_code = UtilityCode.load_cached("RaiseException", "Exceptions.c")
get_exception_utility_code = UtilityCode.load_cached("GetException", "Exceptions.c")
swap_exception_utility_code = UtilityCode.load_cached("SwapException", "Exceptions.c")
unraisable_exception_utility_code = UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c")
reset_exception_utility_code = UtilityCode.load_cached("SaveResetException", "Exceptions.c")
7951
traceback_utility_code = UtilityCode.load_cached("AddTraceback", "Exceptions.c")
7952 7953 7954 7955 7956 7957

#------------------------------------------------------------------------------------

get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
""",
7958 7959 7960
# I doubt that calling __Pyx_GetException() here is correct as it moves
# the exception from tstate->curexc_* to tstate->exc_*, which prevents
# exception handlers later on from receiving it.
7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
    PyObject *type = NULL, *value = NULL, *tb = NULL;
    if (__Pyx_GetException(&type, &value, &tb) == 0) {
        PyObject* exc_info = PyTuple_New(3);
        if (exc_info) {
            Py_INCREF(type);
            Py_INCREF(value);
            Py_INCREF(tb);
            PyTuple_SET_ITEM(exc_info, 0, type);
            PyTuple_SET_ITEM(exc_info, 1, value);
            PyTuple_SET_ITEM(exc_info, 2, tb);
            return exc_info;
        }
    }
    return NULL;
}
""",
requires=[get_exception_utility_code])

#------------------------------------------------------------------------------------
William Stein's avatar
William Stein committed
7982

7983 7984
set_vtable_utility_code = UtilityCode(
proto = """
7985
static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
7986 7987
""",
impl = """
William Stein's avatar
William Stein committed
7988
static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
7989
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
7990
    PyObject *ob = PyCapsule_New(vtable, 0, 0);
7991 7992
#else
    PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
7993 7994
#endif
    if (!ob)
William Stein's avatar
William Stein committed
7995
        goto bad;
7996
    if (PyDict_SetItemString(dict, "__pyx_vtable__", ob) < 0)
William Stein's avatar
William Stein committed
7997
        goto bad;
7998 7999
    Py_DECREF(ob);
    return 0;
William Stein's avatar
William Stein committed
8000
bad:
8001 8002
    Py_XDECREF(ob);
    return -1;
William Stein's avatar
William Stein committed
8003
}
8004
""")
William Stein's avatar
William Stein committed
8005 8006 8007

#------------------------------------------------------------------------------------

8008 8009
get_vtable_utility_code = UtilityCode(
proto = """
8010
static void* __Pyx_GetVtable(PyObject *dict); /*proto*/
8011 8012
""",
impl = r"""
8013 8014
static void* __Pyx_GetVtable(PyObject *dict) {
    void* ptr;
8015 8016
    PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
    if (!ob)
William Stein's avatar
William Stein committed
8017
        goto bad;
8018
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
8019
    ptr = PyCapsule_GetPointer(ob, 0);
8020
#else
8021
    ptr = PyCObject_AsVoidPtr(ob);
8022
#endif
8023 8024
    if (!ptr && !PyErr_Occurred())
        PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type");
8025
    Py_DECREF(ob);
8026
    return ptr;
William Stein's avatar
William Stein committed
8027
bad:
8028
    Py_XDECREF(ob);
8029
    return NULL;
William Stein's avatar
William Stein committed
8030
}
8031
""")
William Stein's avatar
William Stein committed
8032 8033 8034

#------------------------------------------------------------------------------------

8035 8036
init_string_tab_utility_code = UtilityCode(
proto = """
8037
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
8038 8039
""",
impl = """
William Stein's avatar
William Stein committed
8040 8041
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
    while (t->p) {
8042
        #if PY_MAJOR_VERSION < 3
8043
        if (t->is_unicode) {
8044
            *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
8045 8046
        } else if (t->intern) {
            *t->p = PyString_InternFromString(t->s);
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
8047 8048
        } else {
            *t->p = PyString_FromStringAndSize(t->s, t->n - 1);
Stefan Behnel's avatar
Stefan Behnel committed
8049
        }
8050
        #else  /* Python 3+ has unicode identifiers */
8051 8052 8053 8054 8055 8056 8057 8058
        if (t->is_unicode | t->is_str) {
            if (t->intern) {
                *t->p = PyUnicode_InternFromString(t->s);
            } else if (t->encoding) {
                *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL);
            } else {
                *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
            }
Dag Sverre Seljebotn's avatar
Merge  
Dag Sverre Seljebotn committed
8059 8060
        } else {
            *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
Stefan Behnel's avatar
Stefan Behnel committed
8061
        }
8062
        #endif
William Stein's avatar
William Stein committed
8063 8064 8065 8066 8067 8068
        if (!*t->p)
            return -1;
        ++t;
    }
    return 0;
}
8069
""")
William Stein's avatar
William Stein committed
8070 8071

#------------------------------------------------------------------------------------
8072

8073 8074
# Note that cPython ignores PyTrace_EXCEPTION,
# but maybe some other profilers don't.
Robert Bradshaw's avatar
Robert Bradshaw committed
8075

8076 8077
profile_utility_code = UtilityCode(proto="""
#ifndef CYTHON_PROFILE
8078
  #define CYTHON_PROFILE 1
8079 8080
#endif

8081
#ifndef CYTHON_PROFILE_REUSE_FRAME
8082
  #define CYTHON_PROFILE_REUSE_FRAME 0
8083
#endif
Robert Bradshaw's avatar
Robert Bradshaw committed
8084

8085
#if CYTHON_PROFILE
Robert Bradshaw's avatar
Robert Bradshaw committed
8086

8087 8088 8089
  #include "compile.h"
  #include "frameobject.h"
  #include "traceback.h"
8090

8091 8092 8093 8094 8095 8096 8097
  #if CYTHON_PROFILE_REUSE_FRAME
    #define CYTHON_FRAME_MODIFIER static
    #define CYTHON_FRAME_DEL
  #else
    #define CYTHON_FRAME_MODIFIER
    #define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s)
  #endif
Robert Bradshaw's avatar
Robert Bradshaw committed
8098

8099 8100 8101
  #define __Pyx_TraceDeclarations                                  \\
  static PyCodeObject *%(FRAME_CODE)s = NULL;                      \\
  CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL;           \\
8102
  int __Pyx_use_tracing = 0;
8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127

  #define __Pyx_TraceCall(funcname, srcfile, firstlineno)                            \\
  if (unlikely(PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc)) {      \\
      __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno);  \\
  }

  #define __Pyx_TraceException()                                                           \\
  if (unlikely(__Pyx_use_tracing( && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) {  \\
      PyObject *exc_info = __Pyx_GetExceptionTuple();                                      \\
      if (exc_info) {                                                                      \\
          PyThreadState_GET()->c_profilefunc(                                              \\
              PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info);  \\
          Py_DECREF(exc_info);                                                             \\
      }                                                                                    \\
  }

  #define __Pyx_TraceReturn(result)                                                  \\
  if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) {  \\
      PyThreadState_GET()->c_profilefunc(                                            \\
          PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result);     \\
      CYTHON_FRAME_DEL;                                                               \\
  }

  static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
  static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
Robert Bradshaw's avatar
Robert Bradshaw committed
8128

8129
#else
Robert Bradshaw's avatar
Robert Bradshaw committed
8130

8131
  #define __Pyx_TraceDeclarations
8132 8133 8134
  #define __Pyx_TraceCall(funcname, srcfile, firstlineno)
  #define __Pyx_TraceException()
  #define __Pyx_TraceReturn(result)
Robert Bradshaw's avatar
Robert Bradshaw committed
8135

8136
#endif /* CYTHON_PROFILE */
8137
"""
Robert Bradshaw's avatar
Robert Bradshaw committed
8138 8139 8140 8141 8142 8143
% {
    "FRAME": Naming.frame_cname,
    "FRAME_CODE": Naming.frame_code_cname,
},
impl = """

8144
#if CYTHON_PROFILE
Robert Bradshaw's avatar
Robert Bradshaw committed
8145 8146 8147 8148 8149 8150

static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
                                   PyFrameObject** frame,
                                   const char *funcname,
                                   const char *srcfile,
                                   int firstlineno) {
8151
    if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
Robert Bradshaw's avatar
Robert Bradshaw committed
8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203
        if (*code == NULL) {
            *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
            if (*code == NULL) return 0;
        }
        *frame = PyFrame_New(
            PyThreadState_GET(),            /*PyThreadState *tstate*/
            *code,                          /*PyCodeObject *code*/
            PyModule_GetDict(%(MODULE)s),      /*PyObject *globals*/
            0                               /*PyObject *locals*/
        );
        if (*frame == NULL) return 0;
    }
    else {
        (*frame)->f_tstate = PyThreadState_GET();
    }
    return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
}

static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
    PyObject *py_srcfile = 0;
    PyObject *py_funcname = 0;
    PyCodeObject *py_code = 0;

    #if PY_MAJOR_VERSION < 3
    py_funcname = PyString_FromString(funcname);
    py_srcfile = PyString_FromString(srcfile);
    #else
    py_funcname = PyUnicode_FromString(funcname);
    py_srcfile = PyUnicode_FromString(srcfile);
    #endif
    if (!py_funcname | !py_srcfile) goto bad;

    py_code = PyCode_New(
        0,                /*int argcount,*/
        #if PY_MAJOR_VERSION >= 3
        0,                /*int kwonlyargcount,*/
        #endif
        0,                /*int nlocals,*/
        0,                /*int stacksize,*/
        0,                /*int flags,*/
        %(EMPTY_BYTES)s,  /*PyObject *code,*/
        %(EMPTY_TUPLE)s,  /*PyObject *consts,*/
        %(EMPTY_TUPLE)s,  /*PyObject *names,*/
        %(EMPTY_TUPLE)s,  /*PyObject *varnames,*/
        %(EMPTY_TUPLE)s,  /*PyObject *freevars,*/
        %(EMPTY_TUPLE)s,  /*PyObject *cellvars,*/
        py_srcfile,       /*PyObject *filename,*/
        py_funcname,      /*PyObject *name,*/
        firstlineno,      /*int firstlineno,*/
        %(EMPTY_BYTES)s   /*PyObject *lnotab*/
    );

8204
bad:
Robert Bradshaw's avatar
Robert Bradshaw committed
8205 8206
    Py_XDECREF(py_srcfile);
    Py_XDECREF(py_funcname);
8207

Robert Bradshaw's avatar
Robert Bradshaw committed
8208 8209 8210
    return py_code;
}

8211
#endif /* CYTHON_PROFILE */
Robert Bradshaw's avatar
Robert Bradshaw committed
8212 8213 8214 8215 8216
""" % {
    'EMPTY_TUPLE' : Naming.empty_tuple,
    'EMPTY_BYTES' : Naming.empty_bytes,
    "MODULE": Naming.module_cname,
})
8217 8218 8219

################ Utility code for cython.parallel stuff ################

8220 8221 8222
invalid_values_utility_code = UtilityCode(
proto="""\
#include <string.h>
8223

8224
void __pyx_init_nan(void);
8225

8226 8227 8228 8229 8230 8231
static float %(PYX_NAN)s;
"""  % vars(Naming),

init="""
/* Initialize NaN. The sign is irrelevant, an exponent with all bits 1 and
   a nonzero mantissa means NaN. If the first bit in the mantissa is 1, it is
8232
   a quiet NaN. */
8233 8234
    memset(&%(PYX_NAN)s, 0xFF, sizeof(%(PYX_NAN)s));
""" % vars(Naming))
8235

8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251
#------------------------------------------------------------------------------------

raise_import_error_utility_code = UtilityCode(
proto = '''
static CYTHON_INLINE void __Pyx_RaiseImportError(PyObject *name);
''',
impl = '''
static CYTHON_INLINE void __Pyx_RaiseImportError(PyObject *name) {
#if PY_MAJOR_VERSION < 3
    PyErr_Format(PyExc_ImportError, "cannot import name %.230s",
                 PyString_AsString(name));
#else
    PyErr_Format(PyExc_ImportError, "cannot import name %S", name);
#endif
}
''')