1import cython
2cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
3               Options=object, UtilNodes=object, LetNode=object,
4               LetRefNode=object, TreeFragment=object, EncodedString=object,
5               error=object, warning=object, copy=object)
6
7import PyrexTypes
8import Naming
9import ExprNodes
10import Nodes
11import Options
12import Builtin
13
14from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
15from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
16from Cython.Compiler.UtilNodes import LetNode, LetRefNode, ResultRefNode
17from Cython.Compiler.TreeFragment import TreeFragment
18from Cython.Compiler.StringEncoding import EncodedString
19from Cython.Compiler.Errors import error, warning, CompileError, InternalError
20from Cython.Compiler.Code import UtilityCode
21
22import copy
23
24
25class NameNodeCollector(TreeVisitor):
26    """Collect all NameNodes of a (sub-)tree in the ``name_nodes``
27    attribute.
28    """
29    def __init__(self):
30        super(NameNodeCollector, self).__init__()
31        self.name_nodes = []
32
33    def visit_NameNode(self, node):
34        self.name_nodes.append(node)
35
36    def visit_Node(self, node):
37        self._visitchildren(node, None)
38
39
40class SkipDeclarations(object):
41    """
42    Variable and function declarations can often have a deep tree structure,
43    and yet most transformations don't need to descend to this depth.
44
45    Declaration nodes are removed after AnalyseDeclarationsTransform, so there
46    is no need to use this for transformations after that point.
47    """
48    def visit_CTypeDefNode(self, node):
49        return node
50
51    def visit_CVarDefNode(self, node):
52        return node
53
54    def visit_CDeclaratorNode(self, node):
55        return node
56
57    def visit_CBaseTypeNode(self, node):
58        return node
59
60    def visit_CEnumDefNode(self, node):
61        return node
62
63    def visit_CStructOrUnionDefNode(self, node):
64        return node
65
66class NormalizeTree(CythonTransform):
67    """
68    This transform fixes up a few things after parsing
69    in order to make the parse tree more suitable for
70    transforms.
71
72    a) After parsing, blocks with only one statement will
73    be represented by that statement, not by a StatListNode.
74    When doing transforms this is annoying and inconsistent,
75    as one cannot in general remove a statement in a consistent
76    way and so on. This transform wraps any single statements
77    in a StatListNode containing a single statement.
78
79    b) The PassStatNode is a noop and serves no purpose beyond
80    plugging such one-statement blocks; i.e., once parsed a
81`    "pass" can just as well be represented using an empty
82    StatListNode. This means less special cases to worry about
83    in subsequent transforms (one always checks to see if a
84    StatListNode has no children to see if the block is empty).
85    """
86
87    def __init__(self, context):
88        super(NormalizeTree, self).__init__(context)
89        self.is_in_statlist = False
90        self.is_in_expr = False
91
92    def visit_ExprNode(self, node):
93        stacktmp = self.is_in_expr
94        self.is_in_expr = True
95        self.visitchildren(node)
96        self.is_in_expr = stacktmp
97        return node
98
99    def visit_StatNode(self, node, is_listcontainer=False):
100        stacktmp = self.is_in_statlist
101        self.is_in_statlist = is_listcontainer
102        self.visitchildren(node)
103        self.is_in_statlist = stacktmp
104        if not self.is_in_statlist and not self.is_in_expr:
105            return Nodes.StatListNode(pos=node.pos, stats=[node])
106        else:
107            return node
108
109    def visit_StatListNode(self, node):
110        self.is_in_statlist = True
111        self.visitchildren(node)
112        self.is_in_statlist = False
113        return node
114
115    def visit_ParallelAssignmentNode(self, node):
116        return self.visit_StatNode(node, True)
117
118    def visit_CEnumDefNode(self, node):
119        return self.visit_StatNode(node, True)
120
121    def visit_CStructOrUnionDefNode(self, node):
122        return self.visit_StatNode(node, True)
123
124    def visit_PassStatNode(self, node):
125        """Eliminate PassStatNode"""
126        if not self.is_in_statlist:
127            return Nodes.StatListNode(pos=node.pos, stats=[])
128        else:
129            return []
130
131    def visit_ExprStatNode(self, node):
132        """Eliminate useless string literals"""
133        if node.expr.is_string_literal:
134            return self.visit_PassStatNode(node)
135        else:
136            return self.visit_StatNode(node)
137
138    def visit_CDeclaratorNode(self, node):
139        return node
140
141
142class PostParseError(CompileError): pass
143
144# error strings checked by unit tests, so define them
145ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
146ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
147ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
148class PostParse(ScopeTrackingTransform):
149    """
150    Basic interpretation of the parse tree, as well as validity
151    checking that can be done on a very basic level on the parse
152    tree (while still not being a problem with the basic syntax,
153    as such).
154
155    Specifically:
156    - Default values to cdef assignments are turned into single
157    assignments following the declaration (everywhere but in class
158    bodies, where they raise a compile error)
159
160    - Interpret some node structures into Python runtime values.
161    Some nodes take compile-time arguments (currently:
162    TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
163    which should be interpreted. This happens in a general way
164    and other steps should be taken to ensure validity.
165
166    Type arguments cannot be interpreted in this way.
167
168    - For __cythonbufferdefaults__ the arguments are checked for
169    validity.
170
171    TemplatedTypeNode has its directives interpreted:
172    Any first positional argument goes into the "dtype" attribute,
173    any "ndim" keyword argument goes into the "ndim" attribute and
174    so on. Also it is checked that the directive combination is valid.
175    - __cythonbufferdefaults__ attributes are parsed and put into the
176    type information.
177
178    Note: Currently Parsing.py does a lot of interpretation and
179    reorganization that can be refactored into this transform
180    if a more pure Abstract Syntax Tree is wanted.
181    """
182
183    def __init__(self, context):
184        super(PostParse, self).__init__(context)
185        self.specialattribute_handlers = {
186            '__cythonbufferdefaults__' : self.handle_bufferdefaults
187        }
188
189    def visit_ModuleNode(self, node):
190        self.lambda_counter = 1
191        self.genexpr_counter = 1
192        return super(PostParse, self).visit_ModuleNode(node)
193
194    def visit_LambdaNode(self, node):
195        # unpack a lambda expression into the corresponding DefNode
196        lambda_id = self.lambda_counter
197        self.lambda_counter += 1
198        node.lambda_name = EncodedString(u'lambda%d' % lambda_id)
199        collector = YieldNodeCollector()
200        collector.visitchildren(node.result_expr)
201        if collector.yields or isinstance(node.result_expr, ExprNodes.YieldExprNode):
202            body = Nodes.ExprStatNode(
203                node.result_expr.pos, expr=node.result_expr)
204        else:
205            body = Nodes.ReturnStatNode(
206                node.result_expr.pos, value=node.result_expr)
207        node.def_node = Nodes.DefNode(
208            node.pos, name=node.name, lambda_name=node.lambda_name,
209            args=node.args, star_arg=node.star_arg,
210            starstar_arg=node.starstar_arg,
211            body=body, doc=None)
212        self.visitchildren(node)
213        return node
214
215    def visit_GeneratorExpressionNode(self, node):
216        # unpack a generator expression into the corresponding DefNode
217        genexpr_id = self.genexpr_counter
218        self.genexpr_counter += 1
219        node.genexpr_name = EncodedString(u'genexpr%d' % genexpr_id)
220
221        node.def_node = Nodes.DefNode(node.pos, name=node.name,
222                                      doc=None,
223                                      args=[], star_arg=None,
224                                      starstar_arg=None,
225                                      body=node.loop)
226        self.visitchildren(node)
227        return node
228
229    # cdef variables
230    def handle_bufferdefaults(self, decl):
231        if not isinstance(decl.default, ExprNodes.DictNode):
232            raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
233        self.scope_node.buffer_defaults_node = decl.default
234        self.scope_node.buffer_defaults_pos = decl.pos
235
236    def visit_CVarDefNode(self, node):
237        # This assumes only plain names and pointers are assignable on
238        # declaration. Also, it makes use of the fact that a cdef decl
239        # must appear before the first use, so we don't have to deal with
240        # "i = 3; cdef int i = i" and can simply move the nodes around.
241        try:
242            self.visitchildren(node)
243            stats = [node]
244            newdecls = []
245            for decl in node.declarators:
246                declbase = decl
247                while isinstance(declbase, Nodes.CPtrDeclaratorNode):
248                    declbase = declbase.base
249                if isinstance(declbase, Nodes.CNameDeclaratorNode):
250                    if declbase.default is not None:
251                        if self.scope_type in ('cclass', 'pyclass', 'struct'):
252                            if isinstance(self.scope_node, Nodes.CClassDefNode):
253                                handler = self.specialattribute_handlers.get(decl.name)
254                                if handler:
255                                    if decl is not declbase:
256                                        raise PostParseError(decl.pos, ERR_INVALID_SPECIALATTR_TYPE)
257                                    handler(decl)
258                                    continue # Remove declaration
259                            raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
260                        first_assignment = self.scope_type != 'module'
261                        stats.append(Nodes.SingleAssignmentNode(node.pos,
262                            lhs=ExprNodes.NameNode(node.pos, name=declbase.name),
263                            rhs=declbase.default, first=first_assignment))
264                        declbase.default = None
265                newdecls.append(decl)
266            node.declarators = newdecls
267            return stats
268        except PostParseError, e:
269            # An error in a cdef clause is ok, simply remove the declaration
270            # and try to move on to report more errors
271            self.context.nonfatal_error(e)
272            return None
273
274    # Split parallel assignments (a,b = b,a) into separate partial
275    # assignments that are executed rhs-first using temps.  This
276    # restructuring must be applied before type analysis so that known
277    # types on rhs and lhs can be matched directly.  It is required in
278    # the case that the types cannot be coerced to a Python type in
279    # order to assign from a tuple.
280
281    def visit_SingleAssignmentNode(self, node):
282        self.visitchildren(node)
283        return self._visit_assignment_node(node, [node.lhs, node.rhs])
284
285    def visit_CascadedAssignmentNode(self, node):
286        self.visitchildren(node)
287        return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
288
289    def _visit_assignment_node(self, node, expr_list):
290        """Flatten parallel assignments into separate single
291        assignments or cascaded assignments.
292        """
293        if sum([ 1 for expr in expr_list
294                 if expr.is_sequence_constructor or expr.is_string_literal ]) < 2:
295            # no parallel assignments => nothing to do
296            return node
297
298        expr_list_list = []
299        flatten_parallel_assignments(expr_list, expr_list_list)
300        temp_refs = []
301        eliminate_rhs_duplicates(expr_list_list, temp_refs)
302
303        nodes = []
304        for expr_list in expr_list_list:
305            lhs_list = expr_list[:-1]
306            rhs = expr_list[-1]
307            if len(lhs_list) == 1:
308                node = Nodes.SingleAssignmentNode(rhs.pos,
309                    lhs = lhs_list[0], rhs = rhs)
310            else:
311                node = Nodes.CascadedAssignmentNode(rhs.pos,
312                    lhs_list = lhs_list, rhs = rhs)
313            nodes.append(node)
314
315        if len(nodes) == 1:
316            assign_node = nodes[0]
317        else:
318            assign_node = Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
319
320        if temp_refs:
321            duplicates_and_temps = [ (temp.expression, temp)
322                                     for temp in temp_refs ]
323            sort_common_subsequences(duplicates_and_temps)
324            for _, temp_ref in duplicates_and_temps[::-1]:
325                assign_node = LetNode(temp_ref, assign_node)
326
327        return assign_node
328
329    def _flatten_sequence(self, seq, result):
330        for arg in seq.args:
331            if arg.is_sequence_constructor:
332                self._flatten_sequence(arg, result)
333            else:
334                result.append(arg)
335        return result
336
337    def visit_DelStatNode(self, node):
338        self.visitchildren(node)
339        node.args = self._flatten_sequence(node, [])
340        return node
341
342    def visit_ExceptClauseNode(self, node):
343        if node.is_except_as:
344            # except-as must delete NameNode target at the end
345            del_target = Nodes.DelStatNode(
346                node.pos,
347                args=[ExprNodes.NameNode(
348                    node.target.pos, name=node.target.name)],
349                ignore_nonexisting=True)
350            node.body = Nodes.StatListNode(
351                node.pos,
352                stats=[Nodes.TryFinallyStatNode(
353                    node.pos,
354                    body=node.body,
355                    finally_clause=Nodes.StatListNode(
356                        node.pos,
357                        stats=[del_target]))])
358        self.visitchildren(node)
359        return node
360
361
362def eliminate_rhs_duplicates(expr_list_list, ref_node_sequence):
363    """Replace rhs items by LetRefNodes if they appear more than once.
364    Creates a sequence of LetRefNodes that set up the required temps
365    and appends them to ref_node_sequence.  The input list is modified
366    in-place.
367    """
368    seen_nodes = set()
369    ref_nodes = {}
370    def find_duplicates(node):
371        if node.is_literal or node.is_name:
372            # no need to replace those; can't include attributes here
373            # as their access is not necessarily side-effect free
374            return
375        if node in seen_nodes:
376            if node not in ref_nodes:
377                ref_node = LetRefNode(node)
378                ref_nodes[node] = ref_node
379                ref_node_sequence.append(ref_node)
380        else:
381            seen_nodes.add(node)
382            if node.is_sequence_constructor:
383                for item in node.args:
384                    find_duplicates(item)
385
386    for expr_list in expr_list_list:
387        rhs = expr_list[-1]
388        find_duplicates(rhs)
389    if not ref_nodes:
390        return
391
392    def substitute_nodes(node):
393        if node in ref_nodes:
394            return ref_nodes[node]
395        elif node.is_sequence_constructor:
396            node.args = list(map(substitute_nodes, node.args))
397        return node
398
399    # replace nodes inside of the common subexpressions
400    for node in ref_nodes:
401        if node.is_sequence_constructor:
402            node.args = list(map(substitute_nodes, node.args))
403
404    # replace common subexpressions on all rhs items
405    for expr_list in expr_list_list:
406        expr_list[-1] = substitute_nodes(expr_list[-1])
407
408def sort_common_subsequences(items):
409    """Sort items/subsequences so that all items and subsequences that
410    an item contains appear before the item itself.  This is needed
411    because each rhs item must only be evaluated once, so its value
412    must be evaluated first and then reused when packing sequences
413    that contain it.
414
415    This implies a partial order, and the sort must be stable to
416    preserve the original order as much as possible, so we use a
417    simple insertion sort (which is very fast for short sequences, the
418    normal case in practice).
419    """
420    def contains(seq, x):
421        for item in seq:
422            if item is x:
423                return True
424            elif item.is_sequence_constructor and contains(item.args, x):
425                return True
426        return False
427    def lower_than(a,b):
428        return b.is_sequence_constructor and contains(b.args, a)
429
430    for pos, item in enumerate(items):
431        key = item[1] # the ResultRefNode which has already been injected into the sequences
432        new_pos = pos
433        for i in xrange(pos-1, -1, -1):
434            if lower_than(key, items[i][0]):
435                new_pos = i
436        if new_pos != pos:
437            for i in xrange(pos, new_pos, -1):
438                items[i] = items[i-1]
439            items[new_pos] = item
440
441def unpack_string_to_character_literals(literal):
442    chars = []
443    pos = literal.pos
444    stype = literal.__class__
445    sval = literal.value
446    sval_type = sval.__class__
447    for char in sval:
448        cval = sval_type(char)
449        chars.append(stype(pos, value=cval, constant_result=cval))
450    return chars
451
452def flatten_parallel_assignments(input, output):
453    #  The input is a list of expression nodes, representing the LHSs
454    #  and RHS of one (possibly cascaded) assignment statement.  For
455    #  sequence constructors, rearranges the matching parts of both
456    #  sides into a list of equivalent assignments between the
457    #  individual elements.  This transformation is applied
458    #  recursively, so that nested structures get matched as well.
459    rhs = input[-1]
460    if (not (rhs.is_sequence_constructor or isinstance(rhs, ExprNodes.UnicodeNode))
461        or not sum([lhs.is_sequence_constructor for lhs in input[:-1]])):
462        output.append(input)
463        return
464
465    complete_assignments = []
466
467    if rhs.is_sequence_constructor:
468        rhs_args = rhs.args
469    elif rhs.is_string_literal:
470        rhs_args = unpack_string_to_character_literals(rhs)
471
472    rhs_size = len(rhs_args)
473    lhs_targets = [ [] for _ in xrange(rhs_size) ]
474    starred_assignments = []
475    for lhs in input[:-1]:
476        if not lhs.is_sequence_constructor:
477            if lhs.is_starred:
478                error(lhs.pos, "starred assignment target must be in a list or tuple")
479            complete_assignments.append(lhs)
480            continue
481        lhs_size = len(lhs.args)
482        starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
483        if starred_targets > 1:
484            error(lhs.pos, "more than 1 starred expression in assignment")
485            output.append([lhs,rhs])
486            continue
487        elif lhs_size - starred_targets > rhs_size:
488            error(lhs.pos, "need more than %d value%s to unpack"
489                  % (rhs_size, (rhs_size != 1) and 's' or ''))
490            output.append([lhs,rhs])
491            continue
492        elif starred_targets:
493            map_starred_assignment(lhs_targets, starred_assignments,
494                                   lhs.args, rhs_args)
495        elif lhs_size < rhs_size:
496            error(lhs.pos, "too many values to unpack (expected %d, got %d)"
497                  % (lhs_size, rhs_size))
498            output.append([lhs,rhs])
499            continue
500        else:
501            for targets, expr in zip(lhs_targets, lhs.args):
502                targets.append(expr)
503
504    if complete_assignments:
505        complete_assignments.append(rhs)
506        output.append(complete_assignments)
507
508    # recursively flatten partial assignments
509    for cascade, rhs in zip(lhs_targets, rhs_args):
510        if cascade:
511            cascade.append(rhs)
512            flatten_parallel_assignments(cascade, output)
513
514    # recursively flatten starred assignments
515    for cascade in starred_assignments:
516        if cascade[0].is_sequence_constructor:
517            flatten_parallel_assignments(cascade, output)
518        else:
519            output.append(cascade)
520
521def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
522    # Appends the fixed-position LHS targets to the target list that
523    # appear left and right of the starred argument.
524    #
525    # The starred_assignments list receives a new tuple
526    # (lhs_target, rhs_values_list) that maps the remaining arguments
527    # (those that match the starred target) to a list.
528
529    # left side of the starred target
530    for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
531        if expr.is_starred:
532            starred = i
533            lhs_remaining = len(lhs_args) - i - 1
534            break
535        targets.append(expr)
536    else:
537        raise InternalError("no starred arg found when splitting starred assignment")
538
539    # right side of the starred target
540    for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
541                                            lhs_args[starred + 1:])):
542        targets.append(expr)
543
544    # the starred target itself, must be assigned a (potentially empty) list
545    target = lhs_args[starred].target # unpack starred node
546    starred_rhs = rhs_args[starred:]
547    if lhs_remaining:
548        starred_rhs = starred_rhs[:-lhs_remaining]
549    if starred_rhs:
550        pos = starred_rhs[0].pos
551    else:
552        pos = target.pos
553    starred_assignments.append([
554        target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
555
556
557class PxdPostParse(CythonTransform, SkipDeclarations):
558    """
559    Basic interpretation/validity checking that should only be
560    done on pxd trees.
561
562    A lot of this checking currently happens in the parser; but
563    what is listed below happens here.
564
565    - "def" functions are let through only if they fill the
566    getbuffer/releasebuffer slots
567
568    - cdef functions are let through only if they are on the
569    top level and are declared "inline"
570    """
571    ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'"
572    ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'"
573
574    def __call__(self, node):
575        self.scope_type = 'pxd'
576        return super(PxdPostParse, self).__call__(node)
577
578    def visit_CClassDefNode(self, node):
579        old = self.scope_type
580        self.scope_type = 'cclass'
581        self.visitchildren(node)
582        self.scope_type = old
583        return node
584
585    def visit_FuncDefNode(self, node):
586        # FuncDefNode always come with an implementation (without
587        # an imp they are CVarDefNodes..)
588        err = self.ERR_INLINE_ONLY
589
590        if (isinstance(node, Nodes.DefNode) and self.scope_type == 'cclass'
591            and node.name in ('__getbuffer__', '__releasebuffer__')):
592            err = None # allow these slots
593
594        if isinstance(node, Nodes.CFuncDefNode):
595            if (u'inline' in node.modifiers and
596                self.scope_type in ('pxd', 'cclass')):
597                node.inline_in_pxd = True
598                if node.visibility != 'private':
599                    err = self.ERR_NOGO_WITH_INLINE % node.visibility
600                elif node.api:
601                    err = self.ERR_NOGO_WITH_INLINE % 'api'
602                else:
603                    err = None # allow inline function
604            else:
605                err = self.ERR_INLINE_ONLY
606
607        if err:
608            self.context.nonfatal_error(PostParseError(node.pos, err))
609            return None
610        else:
611            return node
612
613class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
614    """
615    After parsing, directives can be stored in a number of places:
616    - #cython-comments at the top of the file (stored in ModuleNode)
617    - Command-line arguments overriding these
618    - @cython.directivename decorators
619    - with cython.directivename: statements
620
621    This transform is responsible for interpreting these various sources
622    and store the directive in two ways:
623    - Set the directives attribute of the ModuleNode for global directives.
624    - Use a CompilerDirectivesNode to override directives for a subtree.
625
626    (The first one is primarily to not have to modify with the tree
627    structure, so that ModuleNode stay on top.)
628
629    The directives are stored in dictionaries from name to value in effect.
630    Each such dictionary is always filled in for all possible directives,
631    using default values where no value is given by the user.
632
633    The available directives are controlled in Options.py.
634
635    Note that we have to run this prior to analysis, and so some minor
636    duplication of functionality has to occur: We manually track cimports
637    and which names the "cython" module may have been imported to.
638    """
639    unop_method_nodes = {
640        'typeof': ExprNodes.TypeofNode,
641
642        'operator.address': ExprNodes.AmpersandNode,
643        'operator.dereference': ExprNodes.DereferenceNode,
644        'operator.preincrement' : ExprNodes.inc_dec_constructor(True, '++'),
645        'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'),
646        'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'),
647        'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'),
648
649        # For backwards compatability.
650        'address': ExprNodes.AmpersandNode,
651    }
652
653    binop_method_nodes = {
654        'operator.comma'        : ExprNodes.c_binop_constructor(','),
655    }
656
657    special_methods = set(['declare', 'union', 'struct', 'typedef',
658                           'sizeof', 'cast', 'pointer', 'compiled',
659                           'NULL', 'fused_type', 'parallel'])
660    special_methods.update(unop_method_nodes.keys())
661
662    valid_parallel_directives = set([
663        "parallel",
664        "prange",
665        "threadid",
666#        "threadsavailable",
667    ])
668
669    def __init__(self, context, compilation_directive_defaults):
670        super(InterpretCompilerDirectives, self).__init__(context)
671        self.compilation_directive_defaults = {}
672        for key, value in compilation_directive_defaults.items():
673            self.compilation_directive_defaults[unicode(key)] = copy.deepcopy(value)
674        self.cython_module_names = set()
675        self.directive_names = {}
676        self.parallel_directives = {}
677
678    def check_directive_scope(self, pos, directive, scope):
679        legal_scopes = Options.directive_scopes.get(directive, None)
680        if legal_scopes and scope not in legal_scopes:
681            self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
682                                        'is not allowed in %s scope' % (directive, scope)))
683            return False
684        else:
685            if (directive not in Options.directive_defaults
686                    and directive not in Options.directive_types):
687                error(pos, "Invalid directive: '%s'." % (directive,))
688            return True
689
690    # Set up processing and handle the cython: comments.
691    def visit_ModuleNode(self, node):
692        for key, value in node.directive_comments.items():
693            if not self.check_directive_scope(node.pos, key, 'module'):
694                self.wrong_scope_error(node.pos, key, 'module')
695                del node.directive_comments[key]
696
697        self.module_scope = node.scope
698
699        directives = copy.deepcopy(Options.directive_defaults)
700        directives.update(copy.deepcopy(self.compilation_directive_defaults))
701        directives.update(node.directive_comments)
702        self.directives = directives
703        node.directives = directives
704        node.parallel_directives = self.parallel_directives
705        self.visitchildren(node)
706        node.cython_module_names = self.cython_module_names
707        return node
708
709    # The following four functions track imports and cimports that
710    # begin with "cython"
711    def is_cython_directive(self, name):
712        return (name in Options.directive_types or
713                name in self.special_methods or
714                PyrexTypes.parse_basic_type(name))
715
716    def is_parallel_directive(self, full_name, pos):
717        """
718        Checks to see if fullname (e.g. cython.parallel.prange) is a valid
719        parallel directive. If it is a star import it also updates the
720        parallel_directives.
721        """
722        result = (full_name + ".").startswith("cython.parallel.")
723
724        if result:
725            directive = full_name.split('.')
726            if full_name == u"cython.parallel":
727                self.parallel_directives[u"parallel"] = u"cython.parallel"
728            elif full_name == u"cython.parallel.*":
729                for name in self.valid_parallel_directives:
730                    self.parallel_directives[name] = u"cython.parallel.%s" % name
731            elif (len(directive) != 3 or
732                  directive[-1] not in self.valid_parallel_directives):
733                error(pos, "No such directive: %s" % full_name)
734
735            self.module_scope.use_utility_code(
736                UtilityCode.load_cached("InitThreads", "ModuleSetupCode.c"))
737
738        return result
739
740    def visit_CImportStatNode(self, node):
741        if node.module_name == u"cython":
742            self.cython_module_names.add(node.as_name or u"cython")
743        elif node.module_name.startswith(u"cython."):
744            if node.module_name.startswith(u"cython.parallel."):
745                error(node.pos, node.module_name + " is not a module")
746            if node.module_name == u"cython.parallel":
747                if node.as_name and node.as_name != u"cython":
748                    self.parallel_directives[node.as_name] = node.module_name
749                else:
750                    self.cython_module_names.add(u"cython")
751                    self.parallel_directives[
752                                    u"cython.parallel"] = node.module_name
753                self.module_scope.use_utility_code(
754                    UtilityCode.load_cached("InitThreads", "ModuleSetupCode.c"))
755            elif node.as_name:
756                self.directive_names[node.as_name] = node.module_name[7:]
757            else:
758                self.cython_module_names.add(u"cython")
759            # if this cimport was a compiler directive, we don't
760            # want to leave the cimport node sitting in the tree
761            return None
762        return node
763
764    def visit_FromCImportStatNode(self, node):
765        if (node.module_name == u"cython") or \
766               node.module_name.startswith(u"cython."):
767            submodule = (node.module_name + u".")[7:]
768            newimp = []
769
770            for pos, name, as_name, kind in node.imported_names:
771                full_name = submodule + name
772                qualified_name = u"cython." + full_name
773
774                if self.is_parallel_directive(qualified_name, node.pos):
775                    # from cython cimport parallel, or
776                    # from cython.parallel cimport parallel, prange, ...
777                    self.parallel_directives[as_name or name] = qualified_name
778                elif self.is_cython_directive(full_name):
779                    if as_name is None:
780                        as_name = full_name
781
782                    self.directive_names[as_name] = full_name
783                    if kind is not None:
784                        self.context.nonfatal_error(PostParseError(pos,
785                            "Compiler directive imports must be plain imports"))
786                else:
787                    newimp.append((pos, name, as_name, kind))
788
789            if not newimp:
790                return None
791
792            node.imported_names = newimp
793        return node
794
795    def visit_FromImportStatNode(self, node):
796        if (node.module.module_name.value == u"cython") or \
797               node.module.module_name.value.startswith(u"cython."):
798            submodule = (node.module.module_name.value + u".")[7:]
799            newimp = []
800            for name, name_node in node.items:
801                full_name = submodule + name
802                qualified_name = u"cython." + full_name
803                if self.is_parallel_directive(qualified_name, node.pos):
804                    self.parallel_directives[name_node.name] = qualified_name
805                elif self.is_cython_directive(full_name):
806                    self.directive_names[name_node.name] = full_name
807                else:
808                    newimp.append((name, name_node))
809            if not newimp:
810                return None
811            node.items = newimp
812        return node
813
814    def visit_SingleAssignmentNode(self, node):
815        if isinstance(node.rhs, ExprNodes.ImportNode):
816            module_name = node.rhs.module_name.value
817            is_parallel = (module_name + u".").startswith(u"cython.parallel.")
818
819            if module_name != u"cython" and not is_parallel:
820                return node
821
822            module_name = node.rhs.module_name.value
823            as_name = node.lhs.name
824
825            node = Nodes.CImportStatNode(node.pos,
826                                         module_name = module_name,
827                                         as_name = as_name)
828            node = self.visit_CImportStatNode(node)
829        else:
830            self.visitchildren(node)
831
832        return node
833
834    def visit_NameNode(self, node):
835        if node.name in self.cython_module_names:
836            node.is_cython_module = True
837        else:
838            node.cython_attribute = self.directive_names.get(node.name)
839        return node
840
841    def try_to_parse_directives(self, node):
842        # If node is the contents of an directive (in a with statement or
843        # decorator), returns a list of (directivename, value) pairs.
844        # Otherwise, returns None
845        if isinstance(node, ExprNodes.CallNode):
846            self.visit(node.function)
847            optname = node.function.as_cython_attribute()
848            if optname:
849                directivetype = Options.directive_types.get(optname)
850                if directivetype:
851                    args, kwds = node.explicit_args_kwds()
852                    directives = []
853                    key_value_pairs = []
854                    if kwds is not None and directivetype is not dict:
855                        for keyvalue in kwds.key_value_pairs:
856                            key, value = keyvalue
857                            sub_optname = "%s.%s" % (optname, key.value)
858                            if Options.directive_types.get(sub_optname):
859                                directives.append(self.try_to_parse_directive(sub_optname, [value], None, keyvalue.pos))
860                            else:
861                                key_value_pairs.append(keyvalue)
862                        if not key_value_pairs:
863                            kwds = None
864                        else:
865                            kwds.key_value_pairs = key_value_pairs
866                        if directives and not kwds and not args:
867                            return directives
868                    directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
869                    return directives
870        elif isinstance(node, (ExprNodes.AttributeNode, ExprNodes.NameNode)):
871            self.visit(node)
872            optname = node.as_cython_attribute()
873            if optname:
874                directivetype = Options.directive_types.get(optname)
875                if directivetype is bool:
876                    return [(optname, True)]
877                elif directivetype is None:
878                    return [(optname, None)]
879                else:
880                    raise PostParseError(
881                        node.pos, "The '%s' directive should be used as a function call." % optname)
882        return None
883
884    def try_to_parse_directive(self, optname, args, kwds, pos):
885        directivetype = Options.directive_types.get(optname)
886        if len(args) == 1 and isinstance(args[0], ExprNodes.NoneNode):
887            return optname, Options.directive_defaults[optname]
888        elif directivetype is bool:
889            if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.BoolNode):
890                raise PostParseError(pos,
891                    'The %s directive takes one compile-time boolean argument' % optname)
892            return (optname, args[0].value)
893        elif directivetype is int:
894            if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.IntNode):
895                raise PostParseError(pos,
896                    'The %s directive takes one compile-time integer argument' % optname)
897            return (optname, int(args[0].value))
898        elif directivetype is str:
899            if kwds is not None or len(args) != 1 or not isinstance(
900                    args[0], (ExprNodes.StringNode, ExprNodes.UnicodeNode)):
901                raise PostParseError(pos,
902                    'The %s directive takes one compile-time string argument' % optname)
903            return (optname, str(args[0].value))
904        elif directivetype is type:
905            if kwds is not None or len(args) != 1:
906                raise PostParseError(pos,
907                    'The %s directive takes one type argument' % optname)
908            return (optname, args[0])
909        elif directivetype is dict:
910            if len(args) != 0:
911                raise PostParseError(pos,
912                    'The %s directive takes no prepositional arguments' % optname)
913            return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
914        elif directivetype is list:
915            if kwds and len(kwds) != 0:
916                raise PostParseError(pos,
917                    'The %s directive takes no keyword arguments' % optname)
918            return optname, [ str(arg.value) for arg in args ]
919        elif callable(directivetype):
920            if kwds is not None or len(args) != 1 or not isinstance(
921                    args[0], (ExprNodes.StringNode, ExprNodes.UnicodeNode)):
922                raise PostParseError(pos,
923                    'The %s directive takes one compile-time string argument' % optname)
924            return (optname, directivetype(optname, str(args[0].value)))
925        else:
926            assert False
927
928    def visit_with_directives(self, body, directives):
929        olddirectives = self.directives
930        newdirectives = copy.copy(olddirectives)
931        newdirectives.update(directives)
932        self.directives = newdirectives
933        assert isinstance(body, Nodes.StatListNode), body
934        retbody = self.visit_Node(body)
935        directive = Nodes.CompilerDirectivesNode(pos=retbody.pos, body=retbody,
936                                                 directives=newdirectives)
937        self.directives = olddirectives
938        return directive
939
940    # Handle decorators
941    def visit_FuncDefNode(self, node):
942        directives = self._extract_directives(node, 'function')
943        if not directives:
944            return self.visit_Node(node)
945        body = Nodes.StatListNode(node.pos, stats=[node])
946        return self.visit_with_directives(body, directives)
947
948    def visit_CVarDefNode(self, node):
949        directives = self._extract_directives(node, 'function')
950        if not directives:
951            return node
952        for name, value in directives.iteritems():
953            if name == 'locals':
954                node.directive_locals = value
955            elif name != 'final':
956                self.context.nonfatal_error(PostParseError(
957                    node.pos,
958                    "Cdef functions can only take cython.locals() "
959                    "or final decorators, got %s." % name))
960        body = Nodes.StatListNode(node.pos, stats=[node])
961        return self.visit_with_directives(body, directives)
962
963    def visit_CClassDefNode(self, node):
964        directives = self._extract_directives(node, 'cclass')
965        if not directives:
966            return self.visit_Node(node)
967        body = Nodes.StatListNode(node.pos, stats=[node])
968        return self.visit_with_directives(body, directives)
969
970    def visit_PyClassDefNode(self, node):
971        directives = self._extract_directives(node, 'class')
972        if not directives:
973            return self.visit_Node(node)
974        body = Nodes.StatListNode(node.pos, stats=[node])
975        return self.visit_with_directives(body, directives)
976
977    def _extract_directives(self, node, scope_name):
978        if not node.decorators:
979            return {}
980        # Split the decorators into two lists -- real decorators and directives
981        directives = []
982        realdecs = []
983        for dec in node.decorators:
984            new_directives = self.try_to_parse_directives(dec.decorator)
985            if new_directives is not None:
986                for directive in new_directives:
987                    if self.check_directive_scope(node.pos, directive[0], scope_name):
988                        directives.append(directive)
989            else:
990                realdecs.append(dec)
991        if realdecs and isinstance(node, (Nodes.CFuncDefNode, Nodes.CClassDefNode, Nodes.CVarDefNode)):
992            raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.")
993        else:
994            node.decorators = realdecs
995        # merge or override repeated directives
996        optdict = {}
997        directives.reverse() # Decorators coming first take precedence
998        for directive in directives:
999            name, value = directive
1000            if name in optdict:
1001                old_value = optdict[name]
1002                # keywords and arg lists can be merged, everything
1003                # else overrides completely
1004                if isinstance(old_value, dict):
1005                    old_value.update(value)
1006                elif isinstance(old_value, list):
1007                    old_value.extend(value)
1008                else:
1009                    optdict[name] = value
1010            else:
1011                optdict[name] = value
1012        return optdict
1013
1014    # Handle with statements
1015    def visit_WithStatNode(self, node):
1016        directive_dict = {}
1017        for directive in self.try_to_parse_directives(node.manager) or []:
1018            if directive is not None:
1019                if node.target is not None:
1020                    self.context.nonfatal_error(
1021                        PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
1022                else:
1023                    name, value = directive
1024                    if name in ('nogil', 'gil'):
1025                        # special case: in pure mode, "with nogil" spells "with cython.nogil"
1026                        node = Nodes.GILStatNode(node.pos, state = name, body = node.body)
1027                        return self.visit_Node(node)
1028                    if self.check_directive_scope(node.pos, name, 'with statement'):
1029                        directive_dict[name] = value
1030        if directive_dict:
1031            return self.visit_with_directives(node.body, directive_dict)
1032        return self.visit_Node(node)
1033
1034
1035class ParallelRangeTransform(CythonTransform, SkipDeclarations):
1036    """
1037    Transform cython.parallel stuff. The parallel_directives come from the
1038    module node, set there by InterpretCompilerDirectives.
1039
1040        x = cython.parallel.threadavailable()   -> ParallelThreadAvailableNode
1041        with nogil, cython.parallel.parallel(): -> ParallelWithBlockNode
1042            print cython.parallel.threadid()    -> ParallelThreadIdNode
1043            for i in cython.parallel.prange(...):  -> ParallelRangeNode
1044                ...
1045    """
1046
1047    # a list of names, maps 'cython.parallel.prange' in the code to
1048    # ['cython', 'parallel', 'prange']
1049    parallel_directive = None
1050
1051    # Indicates whether a namenode in an expression is the cython module
1052    namenode_is_cython_module = False
1053
1054    # Keep track of whether we are the context manager of a 'with' statement
1055    in_context_manager_section = False
1056
1057    # One of 'prange' or 'with parallel'. This is used to disallow closely
1058    # nested 'with parallel:' blocks
1059    state = None
1060
1061    directive_to_node = {
1062        u"cython.parallel.parallel": Nodes.ParallelWithBlockNode,
1063        # u"cython.parallel.threadsavailable": ExprNodes.ParallelThreadsAvailableNode,
1064        u"cython.parallel.threadid": ExprNodes.ParallelThreadIdNode,
1065        u"cython.parallel.prange": Nodes.ParallelRangeNode,
1066    }
1067
1068    def node_is_parallel_directive(self, node):
1069        return node.name in self.parallel_directives or node.is_cython_module
1070
1071    def get_directive_class_node(self, node):
1072        """
1073        Figure out which parallel directive was used and return the associated
1074        Node class.
1075
1076        E.g. for a cython.parallel.prange() call we return ParallelRangeNode
1077        """
1078        if self.namenode_is_cython_module:
1079            directive = '.'.join(self.parallel_directive)
1080        else:
1081            directive = self.parallel_directives[self.parallel_directive[0]]
1082            directive = '%s.%s' % (directive,
1083                                   '.'.join(self.parallel_directive[1:]))
1084            directive = directive.rstrip('.')
1085
1086        cls = self.directive_to_node.get(directive)
1087        if cls is None and not (self.namenode_is_cython_module and
1088                                self.parallel_directive[0] != 'parallel'):
1089            error(node.pos, "Invalid directive: %s" % directive)
1090
1091        self.namenode_is_cython_module = False
1092        self.parallel_directive = None
1093
1094        return cls
1095
1096    def visit_ModuleNode(self, node):
1097        """
1098        If any parallel directives were imported, copy them over and visit
1099        the AST
1100        """
1101        if node.parallel_directives:
1102            self.parallel_directives = node.parallel_directives
1103            return self.visit_Node(node)
1104
1105        # No parallel directives were imported, so they can't be used :)
1106        return node
1107
1108    def visit_NameNode(self, node):
1109        if self.node_is_parallel_directive(node):
1110            self.parallel_directive = [node.name]
1111            self.namenode_is_cython_module = node.is_cython_module
1112        return node
1113
1114    def visit_AttributeNode(self, node):
1115        self.visitchildren(node)
1116        if self.parallel_directive:
1117            self.parallel_directive.append(node.attribute)
1118        return node
1119
1120    def visit_CallNode(self, node):
1121        self.visit(node.function)
1122        if not self.parallel_directive:
1123            return node
1124
1125        # We are a parallel directive, replace this node with the
1126        # corresponding ParallelSomethingSomething node
1127
1128        if isinstance(node, ExprNodes.GeneralCallNode):
1129            args = node.positional_args.args
1130            kwargs = node.keyword_args
1131        else:
1132            args = node.args
1133            kwargs = {}
1134
1135        parallel_directive_class = self.get_directive_class_node(node)
1136        if parallel_directive_class:
1137            # Note: in case of a parallel() the body is set by
1138            # visit_WithStatNode
1139            node = parallel_directive_class(node.pos, args=args, kwargs=kwargs)
1140
1141        return node
1142
1143    def visit_WithStatNode(self, node):
1144        "Rewrite with cython.parallel.parallel() blocks"
1145        newnode = self.visit(node.manager)
1146
1147        if isinstance(newnode, Nodes.ParallelWithBlockNode):
1148            if self.state == 'parallel with':
1149                error(node.manager.pos,
1150                      "Nested parallel with blocks are disallowed")
1151
1152            self.state = 'parallel with'
1153            body = self.visit(node.body)
1154            self.state = None
1155
1156            newnode.body = body
1157            return newnode
1158        elif self.parallel_directive:
1159            parallel_directive_class = self.get_directive_class_node(node)
1160
1161            if not parallel_directive_class:
1162                # There was an error, stop here and now
1163                return None
1164
1165            if parallel_directive_class is Nodes.ParallelWithBlockNode:
1166                error(node.pos, "The parallel directive must be called")
1167                return None
1168
1169        node.body = self.visit(node.body)
1170        return node
1171
1172    def visit_ForInStatNode(self, node):
1173        "Rewrite 'for i in cython.parallel.prange(...):'"
1174        self.visit(node.iterator)
1175        self.visit(node.target)
1176
1177        in_prange = isinstance(node.iterator.sequence,
1178                               Nodes.ParallelRangeNode)
1179        previous_state = self.state
1180
1181        if in_prange:
1182            # This will replace the entire ForInStatNode, so copy the
1183            # attributes
1184            parallel_range_node = node.iterator.sequence
1185
1186            parallel_range_node.target = node.target
1187            parallel_range_node.body = node.body
1188            parallel_range_node.else_clause = node.else_clause
1189
1190            node = parallel_range_node
1191
1192            if not isinstance(node.target, ExprNodes.NameNode):
1193                error(node.target.pos,
1194                      "Can only iterate over an iteration variable")
1195
1196            self.state = 'prange'
1197
1198        self.visit(node.body)
1199        self.state = previous_state
1200        self.visit(node.else_clause)
1201        return node
1202
1203    def visit(self, node):
1204        "Visit a node that may be None"
1205        if node is not None:
1206            return super(ParallelRangeTransform, self).visit(node)
1207
1208
1209class WithTransform(CythonTransform, SkipDeclarations):
1210    def visit_WithStatNode(self, node):
1211        self.visitchildren(node, 'body')
1212        pos = node.pos
1213        body, target, manager = node.body, node.target, node.manager
1214        node.enter_call = ExprNodes.SimpleCallNode(
1215            pos, function=ExprNodes.AttributeNode(
1216                pos, obj=ExprNodes.CloneNode(manager),
1217                attribute=EncodedString('__enter__'),
1218                is_special_lookup=True),
1219            args=[],
1220            is_temp=True)
1221        if target is not None:
1222            body = Nodes.StatListNode(
1223                pos, stats = [
1224                    Nodes.WithTargetAssignmentStatNode(
1225                        pos, lhs = target,
1226                        rhs = ResultRefNode(node.enter_call),
1227                        orig_rhs = node.enter_call),
1228                    body])
1229
1230        excinfo_target = ExprNodes.TupleNode(pos, slow=True, args=[
1231            ExprNodes.ExcValueNode(pos) for _ in range(3)])
1232        except_clause = Nodes.ExceptClauseNode(
1233            pos, body=Nodes.IfStatNode(
1234                pos, if_clauses=[
1235                    Nodes.IfClauseNode(
1236                        pos, condition=ExprNodes.NotNode(
1237                            pos, operand=ExprNodes.WithExitCallNode(
1238                                pos, with_stat=node,
1239                                test_if_run=False,
1240                                args=excinfo_target)),
1241                        body=Nodes.ReraiseStatNode(pos),
1242                        ),
1243                    ],
1244                else_clause=None),
1245            pattern=None,
1246            target=None,
1247            excinfo_target=excinfo_target,
1248            )
1249
1250        node.body = Nodes.TryFinallyStatNode(
1251            pos, body=Nodes.TryExceptStatNode(
1252                pos, body=body,
1253                except_clauses=[except_clause],
1254                else_clause=None,
1255                ),
1256            finally_clause=Nodes.ExprStatNode(
1257                pos, expr=ExprNodes.WithExitCallNode(
1258                    pos, with_stat=node,
1259                    test_if_run=True,
1260                    args=ExprNodes.TupleNode(
1261                        pos, args=[ExprNodes.NoneNode(pos) for _ in range(3)]
1262                        ))),
1263            handle_error_case=False,
1264            )
1265        return node
1266
1267    def visit_ExprNode(self, node):
1268        # With statements are never inside expressions.
1269        return node
1270
1271
1272class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations):
1273    """Originally, this was the only place where decorators were
1274    transformed into the corresponding calling code.  Now, this is
1275    done directly in DefNode and PyClassDefNode to avoid reassignments
1276    to the function/class name - except for cdef class methods.  For
1277    those, the reassignment is required as methods are originally
1278    defined in the PyMethodDef struct.
1279
1280    The IndirectionNode allows DefNode to override the decorator
1281    """
1282
1283    def visit_DefNode(self, func_node):
1284        scope_type = self.scope_type
1285        func_node = self.visit_FuncDefNode(func_node)
1286        if scope_type != 'cclass' or not func_node.decorators:
1287            return func_node
1288        return self.handle_decorators(func_node, func_node.decorators,
1289                                      func_node.name)
1290
1291    def handle_decorators(self, node, decorators, name):
1292        decorator_result = ExprNodes.NameNode(node.pos, name = name)
1293        for decorator in decorators[::-1]:
1294            decorator_result = ExprNodes.SimpleCallNode(
1295                decorator.pos,
1296                function = decorator.decorator,
1297                args = [decorator_result])
1298
1299        name_node = ExprNodes.NameNode(node.pos, name = name)
1300        reassignment = Nodes.SingleAssignmentNode(
1301            node.pos,
1302            lhs = name_node,
1303            rhs = decorator_result)
1304
1305        reassignment = Nodes.IndirectionNode([reassignment])
1306        node.decorator_indirection = reassignment
1307        return [node, reassignment]
1308
1309class CnameDirectivesTransform(CythonTransform, SkipDeclarations):
1310    """
1311    Only part of the CythonUtilityCode pipeline. Must be run before
1312    DecoratorTransform in case this is a decorator for a cdef class.
1313    It filters out @cname('my_cname') decorators and rewrites them to
1314    CnameDecoratorNodes.
1315    """
1316
1317    def handle_function(self, node):
1318        if not getattr(node, 'decorators', None):
1319            return self.visit_Node(node)
1320
1321        for i, decorator in enumerate(node.decorators):
1322            decorator = decorator.decorator
1323
1324            if (isinstance(decorator, ExprNodes.CallNode) and
1325                    decorator.function.is_name and
1326                    decorator.function.name == 'cname'):
1327                args, kwargs = decorator.explicit_args_kwds()
1328
1329                if kwargs:
1330                    raise AssertionError(
1331                            "cname decorator does not take keyword arguments")
1332
1333                if len(args) != 1:
1334                    raise AssertionError(
1335                            "cname decorator takes exactly one argument")
1336
1337                if not (args[0].is_literal and
1338                        args[0].type == Builtin.str_type):
1339                    raise AssertionError(
1340                            "argument to cname decorator must be a string literal")
1341
1342                cname = args[0].compile_time_value(None).decode('UTF-8')
1343                del node.decorators[i]
1344                node = Nodes.CnameDecoratorNode(pos=node.pos, node=node,
1345                                                cname=cname)
1346                break
1347
1348        return self.visit_Node(node)
1349
1350    visit_FuncDefNode = handle_function
1351    visit_CClassDefNode = handle_function
1352    visit_CEnumDefNode = handle_function
1353    visit_CStructOrUnionDefNode = handle_function
1354
1355
1356class ForwardDeclareTypes(CythonTransform):
1357
1358    def visit_CompilerDirectivesNode(self, node):
1359        env = self.module_scope
1360        old = env.directives
1361        env.directives = node.directives
1362        self.visitchildren(node)
1363        env.directives = old
1364        return node
1365
1366    def visit_ModuleNode(self, node):
1367        self.module_scope = node.scope
1368        self.module_scope.directives = node.directives
1369        self.visitchildren(node)
1370        return node
1371
1372    def visit_CDefExternNode(self, node):
1373        old_cinclude_flag = self.module_scope.in_cinclude
1374        self.module_scope.in_cinclude = 1
1375        self.visitchildren(node)
1376        self.module_scope.in_cinclude = old_cinclude_flag
1377        return node
1378
1379    def visit_CEnumDefNode(self, node):
1380        node.declare(self.module_scope)
1381        return node
1382
1383    def visit_CStructOrUnionDefNode(self, node):
1384        if node.name not in self.module_scope.entries:
1385            node.declare(self.module_scope)
1386        return node
1387
1388    def visit_CClassDefNode(self, node):
1389        if node.class_name not in self.module_scope.entries:
1390            node.declare(self.module_scope)
1391        return node
1392
1393
1394class AnalyseDeclarationsTransform(EnvTransform):
1395
1396    basic_property = TreeFragment(u"""
1397property NAME:
1398    def __get__(self):
1399        return ATTR
1400    def __set__(self, value):
1401        ATTR = value
1402    """, level='c_class', pipeline=[NormalizeTree(None)])
1403    basic_pyobject_property = TreeFragment(u"""
1404property NAME:
1405    def __get__(self):
1406        return ATTR
1407    def __set__(self, value):
1408        ATTR = value
1409    def __del__(self):
1410        ATTR = None
1411    """, level='c_class', pipeline=[NormalizeTree(None)])
1412    basic_property_ro = TreeFragment(u"""
1413property NAME:
1414    def __get__(self):
1415        return ATTR
1416    """, level='c_class', pipeline=[NormalizeTree(None)])
1417
1418    struct_or_union_wrapper = TreeFragment(u"""
1419cdef class NAME:
1420    cdef TYPE value
1421    def __init__(self, MEMBER=None):
1422        cdef int count
1423        count = 0
1424        INIT_ASSIGNMENTS
1425        if IS_UNION and count > 1:
1426            raise ValueError, "At most one union member should be specified."
1427    def __str__(self):
1428        return STR_FORMAT % MEMBER_TUPLE
1429    def __repr__(self):
1430        return REPR_FORMAT % MEMBER_TUPLE
1431    """, pipeline=[NormalizeTree(None)])
1432
1433    init_assignment = TreeFragment(u"""
1434if VALUE is not None:
1435    ATTR = VALUE
1436    count += 1
1437    """, pipeline=[NormalizeTree(None)])
1438
1439    fused_function = None
1440    in_lambda = 0
1441
1442    def __call__(self, root):
1443        # needed to determine if a cdef var is declared after it's used.
1444        self.seen_vars_stack = []
1445        self.fused_error_funcs = set()
1446        super_class = super(AnalyseDeclarationsTransform, self)
1447        self._super_visit_FuncDefNode = super_class.visit_FuncDefNode
1448        return super_class.__call__(root)
1449
1450    def visit_NameNode(self, node):
1451        self.seen_vars_stack[-1].add(node.name)
1452        return node
1453
1454    def visit_ModuleNode(self, node):
1455        self.seen_vars_stack.append(set())
1456        node.analyse_declarations(self.current_env())
1457        self.visitchildren(node)
1458        self.seen_vars_stack.pop()
1459        return node
1460
1461    def visit_LambdaNode(self, node):
1462        self.in_lambda += 1
1463        node.analyse_declarations(self.current_env())
1464        self.visitchildren(node)
1465        self.in_lambda -= 1
1466        return node
1467
1468    def visit_CClassDefNode(self, node):
1469        node = self.visit_ClassDefNode(node)
1470        if node.scope and node.scope.implemented:
1471            stats = []
1472            for entry in node.scope.var_entries:
1473                if entry.needs_property:
1474                    property = self.create_Property(entry)
1475                    property.analyse_declarations(node.scope)
1476                    self.visit(property)
1477                    stats.append(property)
1478            if stats:
1479                node.body.stats += stats
1480        return node
1481
1482    def _handle_fused_def_decorators(self, old_decorators, env, node):
1483        """
1484        Create function calls to the decorators and reassignments to
1485        the function.
1486        """
1487        # Delete staticmethod and classmethod decorators, this is
1488        # handled directly by the fused function object.
1489        decorators = []
1490        for decorator in old_decorators:
1491            func = decorator.decorator
1492            if (not func.is_name or
1493                func.name not in ('staticmethod', 'classmethod') or
1494                env.lookup_here(func.name)):
1495                # not a static or classmethod
1496                decorators.append(decorator)
1497
1498        if decorators:
1499            transform = DecoratorTransform(self.context)
1500            def_node = node.node
1501            _, reassignments = transform.handle_decorators(
1502                def_node, decorators, def_node.name)
1503            reassignments.analyse_declarations(env)
1504            node = [node, reassignments]
1505
1506        return node
1507
1508    def _handle_def(self, decorators, env, node):
1509        "Handle def or cpdef fused functions"
1510        # Create PyCFunction nodes for each specialization
1511        node.stats.insert(0, node.py_func)
1512        node.py_func = self.visit(node.py_func)
1513        node.update_fused_defnode_entry(env)
1514        pycfunc = ExprNodes.PyCFunctionNode.from_defnode(node.py_func,
1515                                                         True)
1516        pycfunc = ExprNodes.ProxyNode(pycfunc.coerce_to_temp(env))
1517        node.resulting_fused_function = pycfunc
1518        # Create assignment node for our def function
1519        node.fused_func_assignment = self._create_assignment(
1520            node.py_func, ExprNodes.CloneNode(pycfunc), env)
1521
1522        if decorators:
1523            node = self._handle_fused_def_decorators(decorators, env, node)
1524
1525        return node
1526
1527    def _create_fused_function(self, env, node):
1528        "Create a fused function for a DefNode with fused arguments"
1529        from Cython.Compiler import FusedNode
1530
1531        if self.fused_function or self.in_lambda:
1532            if self.fused_function not in self.fused_error_funcs:
1533                if self.in_lambda:
1534                    error(node.pos, "Fused lambdas not allowed")
1535                else:
1536                    error(node.pos, "Cannot nest fused functions")
1537
1538            self.fused_error_funcs.add(self.fused_function)
1539
1540            node.body = Nodes.PassStatNode(node.pos)
1541            for arg in node.args:
1542                if arg.type.is_fused:
1543                    arg.type = arg.type.get_fused_types()[0]
1544
1545            return node
1546
1547        decorators = getattr(node, 'decorators', None)
1548        node = FusedNode.FusedCFuncDefNode(node, env)
1549        self.fused_function = node
1550        self.visitchildren(node)
1551        self.fused_function = None
1552        if node.py_func:
1553            node = self._handle_def(decorators, env, node)
1554
1555        return node
1556
1557    def _handle_nogil_cleanup(self, lenv, node):
1558        "Handle cleanup for 'with gil' blocks in nogil functions."
1559        if lenv.nogil and lenv.has_with_gil_block:
1560            # Acquire the GIL for cleanup in 'nogil' functions, by wrapping
1561            # the entire function body in try/finally.
1562            # The corresponding release will be taken care of by
1563            # Nodes.FuncDefNode.generate_function_definitions()
1564            node.body = Nodes.NogilTryFinallyStatNode(
1565                node.body.pos,
1566                body=node.body,
1567                finally_clause=Nodes.EnsureGILNode(node.body.pos))
1568
1569    def _handle_fused(self, node):
1570        if node.is_generator and node.has_fused_arguments:
1571            node.has_fused_arguments = False
1572            error(node.pos, "Fused generators not supported")
1573            node.gbody = Nodes.StatListNode(node.pos,
1574                                            stats=[],
1575                                            body=Nodes.PassStatNode(node.pos))
1576
1577        return node.has_fused_arguments
1578
1579    def visit_FuncDefNode(self, node):
1580        """
1581        Analyse a function and its body, as that hasn't happend yet. Also
1582        analyse the directive_locals set by @cython.locals(). Then, if we are
1583        a function with fused arguments, replace the function (after it has
1584        declared itself in the symbol table!) with a FusedCFuncDefNode, and
1585        analyse its children (which are in turn normal functions). If we're a
1586        normal function, just analyse the body of the function.
1587        """
1588        env = self.current_env()
1589
1590        self.seen_vars_stack.append(set())
1591        lenv = node.local_scope
1592        node.declare_arguments(lenv)
1593
1594        for var, type_node in node.directive_locals.items():
1595            if not lenv.lookup_here(var):   # don't redeclare args
1596                type = type_node.analyse_as_type(lenv)
1597                if type:
1598                    lenv.declare_var(var, type, type_node.pos)
1599                else:
1600                    error(type_node.pos, "Not a type")
1601
1602        if self._handle_fused(node):
1603            node = self._create_fused_function(env, node)
1604        else:
1605            node.body.analyse_declarations(lenv)
1606            self._handle_nogil_cleanup(lenv, node)
1607            self._super_visit_FuncDefNode(node)
1608
1609        self.seen_vars_stack.pop()
1610        return node
1611
1612    def visit_DefNode(self, node):
1613        node = self.visit_FuncDefNode(node)
1614        env = self.current_env()
1615        if (not isinstance(node, Nodes.DefNode) or
1616            node.fused_py_func or node.is_generator_body or
1617            not node.needs_assignment_synthesis(env)):
1618            return node
1619        return [node, self._synthesize_assignment(node, env)]
1620
1621    def visit_GeneratorBodyDefNode(self, node):
1622        return self.visit_FuncDefNode(node)
1623
1624    def _synthesize_assignment(self, node, env):
1625        # Synthesize assignment node and put it right after defnode
1626        genv = env
1627        while genv.is_py_class_scope or genv.is_c_class_scope:
1628            genv = genv.outer_scope
1629
1630        if genv.is_closure_scope:
1631            rhs = node.py_cfunc_node = ExprNodes.InnerFunctionNode(
1632                node.pos, def_node=node,
1633                pymethdef_cname=node.entry.pymethdef_cname,
1634                code_object=ExprNodes.CodeObjectNode(node))
1635        else:
1636            binding = self.current_directives.get('binding')
1637            rhs = ExprNodes.PyCFunctionNode.from_defnode(node, binding)
1638
1639        if env.is_py_class_scope:
1640            rhs.binding = True
1641
1642        node.is_cyfunction = rhs.binding
1643        return self._create_assignment(node, rhs, env)
1644
1645    def _create_assignment(self, def_node, rhs, env):
1646        if def_node.decorators:
1647            for decorator in def_node.decorators[::-1]:
1648                rhs = ExprNodes.SimpleCallNode(
1649                    decorator.pos,
1650                    function = decorator.decorator,
1651                    args = [rhs])
1652            def_node.decorators = None
1653
1654        assmt = Nodes.SingleAssignmentNode(
1655            def_node.pos,
1656            lhs=ExprNodes.NameNode(def_node.pos, name=def_node.name),
1657            rhs=rhs)
1658        assmt.analyse_declarations(env)
1659        return assmt
1660
1661    def visit_ScopedExprNode(self, node):
1662        env = self.current_env()
1663        node.analyse_declarations(env)
1664        # the node may or may not have a local scope
1665        if node.has_local_scope:
1666            self.seen_vars_stack.append(set(self.seen_vars_stack[-1]))
1667            self.enter_scope(node, node.expr_scope)
1668            node.analyse_scoped_declarations(node.expr_scope)
1669            self.visitchildren(node)
1670            self.exit_scope()
1671            self.seen_vars_stack.pop()
1672        else:
1673            node.analyse_scoped_declarations(env)
1674            self.visitchildren(node)
1675        return node
1676
1677    def visit_TempResultFromStatNode(self, node):
1678        self.visitchildren(node)
1679        node.analyse_declarations(self.current_env())
1680        return node
1681
1682    def visit_CppClassNode(self, node):
1683        if node.visibility == 'extern':
1684            return None
1685        else:
1686            return self.visit_ClassDefNode(node)
1687
1688    def visit_CStructOrUnionDefNode(self, node):
1689        # Create a wrapper node if needed.
1690        # We want to use the struct type information (so it can't happen
1691        # before this phase) but also create new objects to be declared
1692        # (so it can't happen later).
1693        # Note that we don't return the original node, as it is
1694        # never used after this phase.
1695        if True: # private (default)
1696            return None
1697
1698        self_value = ExprNodes.AttributeNode(
1699            pos = node.pos,
1700            obj = ExprNodes.NameNode(pos=node.pos, name=u"self"),
1701            attribute = EncodedString(u"value"))
1702        var_entries = node.entry.type.scope.var_entries
1703        attributes = []
1704        for entry in var_entries:
1705            attributes.append(ExprNodes.AttributeNode(pos = entry.pos,
1706                                                      obj = self_value,
1707                                                      attribute = entry.name))
1708        # __init__ assignments
1709        init_assignments = []
1710        for entry, attr in zip(var_entries, attributes):
1711            # TODO: branch on visibility
1712            init_assignments.append(self.init_assignment.substitute({
1713                    u"VALUE": ExprNodes.NameNode(entry.pos, name = entry.name),
1714                    u"ATTR": attr,
1715                }, pos = entry.pos))
1716
1717        # create the class
1718        str_format = u"%s(%s)" % (node.entry.type.name, ("%s, " * len(attributes))[:-2])
1719        wrapper_class = self.struct_or_union_wrapper.substitute({
1720            u"INIT_ASSIGNMENTS": Nodes.StatListNode(node.pos, stats = init_assignments),
1721            u"IS_UNION": ExprNodes.BoolNode(node.pos, value = not node.entry.type.is_struct),
1722            u"MEMBER_TUPLE": ExprNodes.TupleNode(node.pos, args=attributes),
1723            u"STR_FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(str_format)),
1724            u"REPR_FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(str_format.replace("%s", "%r"))),
1725        }, pos = node.pos).stats[0]
1726        wrapper_class.class_name = node.name
1727        wrapper_class.shadow = True
1728        class_body = wrapper_class.body.stats
1729
1730        # fix value type
1731        assert isinstance(class_body[0].base_type, Nodes.CSimpleBaseTypeNode)
1732        class_body[0].base_type.name = node.name
1733
1734        # fix __init__ arguments
1735        init_method = class_body[1]
1736        assert isinstance(init_method, Nodes.DefNode) and init_method.name == '__init__'
1737        arg_template = init_method.args[1]
1738        if not node.entry.type.is_struct:
1739            arg_template.kw_only = True
1740        del init_method.args[1]
1741        for entry, attr in zip(var_entries, attributes):
1742            arg = copy.deepcopy(arg_template)
1743            arg.declarator.name = entry.name
1744            init_method.args.append(arg)
1745
1746        # setters/getters
1747        for entry, attr in zip(var_entries, attributes):
1748            # TODO: branch on visibility
1749            if entry.type.is_pyobject:
1750                template = self.basic_pyobject_property
1751            else:
1752                template = self.basic_property
1753            property = template.substitute({
1754                    u"ATTR": attr,
1755                }, pos = entry.pos).stats[0]
1756            property.name = entry.name
1757            wrapper_class.body.stats.append(property)
1758
1759        wrapper_class.analyse_declarations(self.current_env())
1760        return self.visit_CClassDefNode(wrapper_class)
1761
1762    # Some nodes are no longer needed after declaration
1763    # analysis and can be dropped. The analysis was performed
1764    # on these nodes in a seperate recursive process from the
1765    # enclosing function or module, so we can simply drop them.
1766    def visit_CDeclaratorNode(self, node):
1767        # necessary to ensure that all CNameDeclaratorNodes are visited.
1768        self.visitchildren(node)
1769        return node
1770
1771    def visit_CTypeDefNode(self, node):
1772        return node
1773
1774    def visit_CBaseTypeNode(self, node):
1775        return None
1776
1777    def visit_CEnumDefNode(self, node):
1778        if node.visibility == 'public':
1779            return node
1780        else:
1781            return None
1782
1783    def visit_CNameDeclaratorNode(self, node):
1784        if node.name in self.seen_vars_stack[-1]:
1785            entry = self.current_env().lookup(node.name)
1786            if (entry is None or entry.visibility != 'extern'
1787                and not entry.scope.is_c_class_scope):
1788                warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
1789        self.visitchildren(node)
1790        return node
1791
1792    def visit_CVarDefNode(self, node):
1793        # to ensure all CNameDeclaratorNodes are visited.
1794        self.visitchildren(node)
1795        return None
1796
1797    def visit_CnameDecoratorNode(self, node):
1798        child_node = self.visit(node.node)
1799        if not child_node:
1800            return None
1801        if type(child_node) is list: # Assignment synthesized
1802            node.child_node = child_node[0]
1803            return [node] + child_node[1:]
1804        node.node = child_node
1805        return node
1806
1807    def create_Property(self, entry):
1808        if entry.visibility == 'public':
1809            if entry.type.is_pyobject:
1810                template = self.basic_pyobject_property
1811            else:
1812                template = self.basic_property
1813        elif entry.visibility == 'readonly':
1814            template = self.basic_property_ro
1815        property = template.substitute({
1816                u"ATTR": ExprNodes.AttributeNode(pos=entry.pos,
1817                                                 obj=ExprNodes.NameNode(pos=entry.pos, name="self"),
1818                                                 attribute=entry.name),
1819            }, pos=entry.pos).stats[0]
1820        property.name = entry.name
1821        property.doc = entry.doc
1822        return property
1823
1824
1825class CalculateQualifiedNamesTransform(EnvTransform):
1826    """
1827    Calculate and store the '__qualname__' and the global
1828    module name on some nodes.
1829    """
1830    def visit_ModuleNode(self, node):
1831        self.module_name = self.global_scope().qualified_name
1832        self.qualified_name = []
1833        _super = super(CalculateQualifiedNamesTransform, self)
1834        self._super_visit_FuncDefNode = _super.visit_FuncDefNode
1835        self._super_visit_ClassDefNode = _super.visit_ClassDefNode
1836        self.visitchildren(node)
1837        return node
1838
1839    def _set_qualname(self, node, name=None):
1840        if name:
1841            qualname = self.qualified_name[:]
1842            qualname.append(name)
1843        else:
1844            qualname = self.qualified_name
1845        node.qualname = EncodedString('.'.join(qualname))
1846        node.module_name = self.module_name
1847        self.visitchildren(node)
1848        return node
1849
1850    def _append_entry(self, entry):
1851        if entry.is_pyglobal and not entry.is_pyclass_attr:
1852            self.qualified_name = [entry.name]
1853        else:
1854            self.qualified_name.append(entry.name)
1855
1856    def visit_ClassNode(self, node):
1857        return self._set_qualname(node, node.name)
1858
1859    def visit_PyClassNamespaceNode(self, node):
1860        # class name was already added by parent node
1861        return self._set_qualname(node)
1862
1863    def visit_PyCFunctionNode(self, node):
1864        return self._set_qualname(node, node.def_node.name)
1865
1866    def visit_FuncDefNode(self, node):
1867        orig_qualified_name = self.qualified_name[:]
1868        if getattr(node, 'name', None) == '<lambda>':
1869            self.qualified_name.append('<lambda>')
1870        else:
1871            self._append_entry(node.entry)
1872        self.qualified_name.append('<locals>')
1873        self._super_visit_FuncDefNode(node)
1874        self.qualified_name = orig_qualified_name
1875        return node
1876
1877    def visit_ClassDefNode(self, node):
1878        orig_qualified_name = self.qualified_name[:]
1879        entry = (getattr(node, 'entry', None) or             # PyClass
1880                 self.current_env().lookup_here(node.name))  # CClass
1881        self._append_entry(entry)
1882        self._super_visit_ClassDefNode(node)
1883        self.qualified_name = orig_qualified_name
1884        return node
1885
1886
1887class AnalyseExpressionsTransform(CythonTransform):
1888
1889    def visit_ModuleNode(self, node):
1890        node.scope.infer_types()
1891        node.body = node.body.analyse_expressions(node.scope)
1892        self.visitchildren(node)
1893        return node
1894
1895    def visit_FuncDefNode(self, node):
1896        node.local_scope.infer_types()
1897        node.body = node.body.analyse_expressions(node.local_scope)
1898        self.visitchildren(node)
1899        return node
1900
1901    def visit_ScopedExprNode(self, node):
1902        if node.has_local_scope:
1903            node.expr_scope.infer_types()
1904            node = node.analyse_scoped_expressions(node.expr_scope)
1905        self.visitchildren(node)
1906        return node
1907
1908    def visit_IndexNode(self, node):
1909        """
1910        Replace index nodes used to specialize cdef functions with fused
1911        argument types with the Attribute- or NameNode referring to the
1912        function. We then need to copy over the specialization properties to
1913        the attribute or name node.
1914
1915        Because the indexing might be a Python indexing operation on a fused
1916        function, or (usually) a Cython indexing operation, we need to
1917        re-analyse the types.
1918        """
1919        self.visit_Node(node)
1920
1921        if node.is_fused_index and not node.type.is_error:
1922            node = node.base
1923        elif node.memslice_ellipsis_noop:
1924            # memoryviewslice[...] expression, drop the IndexNode
1925            node = node.base
1926
1927        return node
1928
1929
1930class FindInvalidUseOfFusedTypes(CythonTransform):
1931
1932    def visit_FuncDefNode(self, node):
1933        # Errors related to use in functions with fused args will already
1934        # have been detected
1935        if not node.has_fused_arguments:
1936            if not node.is_generator_body and node.return_type.is_fused:
1937                error(node.pos, "Return type is not specified as argument type")
1938            else:
1939                self.visitchildren(node)
1940
1941        return node
1942
1943    def visit_ExprNode(self, node):
1944        if node.type and node.type.is_fused:
1945            error(node.pos, "Invalid use of fused types, type cannot be specialized")
1946        else:
1947            self.visitchildren(node)
1948
1949        return node
1950
1951
1952class ExpandInplaceOperators(EnvTransform):
1953
1954    def visit_InPlaceAssignmentNode(self, node):
1955        lhs = node.lhs
1956        rhs = node.rhs
1957        if lhs.type.is_cpp_class:
1958            # No getting around this exact operator here.
1959            return node
1960        if isinstance(lhs, ExprNodes.IndexNode) and lhs.is_buffer_access:
1961            # There is code to handle this case.
1962            return node
1963
1964        env = self.current_env()
1965        def side_effect_free_reference(node, setting=False):
1966            if isinstance(node, ExprNodes.NameNode):
1967                return node, []
1968            elif node.type.is_pyobject and not setting:
1969                node = LetRefNode(node)
1970                return node, [node]
1971            elif isinstance(node, ExprNodes.IndexNode):
1972                if node.is_buffer_access:
1973                    raise ValueError("Buffer access")
1974                base, temps = side_effect_free_reference(node.base)
1975                index = LetRefNode(node.index)
1976                return ExprNodes.IndexNode(node.pos, base=base, index=index), temps + [index]
1977            elif isinstance(node, ExprNodes.AttributeNode):
1978                obj, temps = side_effect_free_reference(node.obj)
1979                return ExprNodes.AttributeNode(node.pos, obj=obj, attribute=node.attribute), temps
1980            else:
1981                node = LetRefNode(node)
1982                return node, [node]
1983        try:
1984            lhs, let_ref_nodes = side_effect_free_reference(lhs, setting=True)
1985        except ValueError:
1986            return node
1987        dup = lhs.__class__(**lhs.__dict__)
1988        binop = ExprNodes.binop_node(node.pos,
1989                                     operator = node.operator,
1990                                     operand1 = dup,
1991                                     operand2 = rhs,
1992                                     inplace=True)
1993        # Manually analyse types for new node.
1994        lhs.analyse_target_types(env)
1995        dup.analyse_types(env)
1996        binop.analyse_operation(env)
1997        node = Nodes.SingleAssignmentNode(
1998            node.pos,
1999            lhs = lhs,
2000            rhs=binop.coerce_to(lhs.type, env))
2001        # Use LetRefNode to avoid side effects.
2002        let_ref_nodes.reverse()
2003        for t in let_ref_nodes:
2004            node = LetNode(t, node)
2005        return node
2006
2007    def visit_ExprNode(self, node):
2008        # In-place assignments can't happen within an expression.
2009        return node
2010
2011class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
2012    """
2013    Adjust function and class definitions by the decorator directives:
2014
2015    @cython.cfunc
2016    @cython.cclass
2017    @cython.ccall
2018    """
2019
2020    def visit_ModuleNode(self, node):
2021        self.directives = node.directives
2022        self.in_py_class = False
2023        self.visitchildren(node)
2024        return node
2025
2026    def visit_CompilerDirectivesNode(self, node):
2027        old_directives = self.directives
2028        self.directives = node.directives
2029        self.visitchildren(node)
2030        self.directives = old_directives
2031        return node
2032
2033    def visit_DefNode(self, node):
2034        if 'ccall' in self.directives:
2035            node = node.as_cfunction(overridable=True, returns=self.directives.get('returns'))
2036            return self.visit(node)
2037        if 'cfunc' in self.directives:
2038            if self.in_py_class:
2039                error(node.pos, "cfunc directive is not allowed here")
2040            else:
2041                node = node.as_cfunction(overridable=False, returns=self.directives.get('returns'))
2042                return self.visit(node)
2043        self.visitchildren(node)
2044        return node
2045
2046    def visit_PyClassDefNode(self, node):
2047        if 'cclass' in self.directives:
2048            node = node.as_cclass()
2049            return self.visit(node)
2050        else:
2051            old_in_pyclass = self.in_py_class
2052            self.in_py_class = True
2053            self.visitchildren(node)
2054            self.in_py_class = old_in_pyclass
2055            return node
2056
2057    def visit_CClassDefNode(self, node):
2058        old_in_pyclass = self.in_py_class
2059        self.in_py_class = False
2060        self.visitchildren(node)
2061        self.in_py_class = old_in_pyclass
2062        return node
2063
2064
2065class AlignFunctionDefinitions(CythonTransform):
2066    """
2067    This class takes the signatures from a .pxd file and applies them to
2068    the def methods in a .py file.
2069    """
2070
2071    def visit_ModuleNode(self, node):
2072        self.scope = node.scope
2073        self.directives = node.directives
2074        self.imported_names = set()  # hack, see visit_FromImportStatNode()
2075        self.visitchildren(node)
2076        return node
2077
2078    def visit_PyClassDefNode(self, node):
2079        pxd_def = self.scope.lookup(node.name)
2080        if pxd_def:
2081            if pxd_def.is_cclass:
2082                return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
2083            elif not pxd_def.scope or not pxd_def.scope.is_builtin_scope:
2084                error(node.pos, "'%s' redeclared" % node.name)
2085                if pxd_def.pos:
2086                    error(pxd_def.pos, "previous declaration here")
2087                return None
2088        return node
2089
2090    def visit_CClassDefNode(self, node, pxd_def=None):
2091        if pxd_def is None:
2092            pxd_def = self.scope.lookup(node.class_name)
2093        if pxd_def:
2094            outer_scope = self.scope
2095            self.scope = pxd_def.type.scope
2096        self.visitchildren(node)
2097        if pxd_def:
2098            self.scope = outer_scope
2099        return node
2100
2101    def visit_DefNode(self, node):
2102        pxd_def = self.scope.lookup(node.name)
2103        if pxd_def and (not pxd_def.scope or not pxd_def.scope.is_builtin_scope):
2104            if not pxd_def.is_cfunction:
2105                error(node.pos, "'%s' redeclared" % node.name)
2106                if pxd_def.pos:
2107                    error(pxd_def.pos, "previous declaration here")
2108                return None
2109            node = node.as_cfunction(pxd_def)
2110        elif (self.scope.is_module_scope and self.directives['auto_cpdef']
2111              and not node.name in self.imported_names
2112              and node.is_cdef_func_compatible()):
2113            # FIXME: cpdef-ing should be done in analyse_declarations()
2114            node = node.as_cfunction(scope=self.scope)
2115        # Enable this when nested cdef functions are allowed.
2116        # self.visitchildren(node)
2117        return node
2118
2119    def visit_FromImportStatNode(self, node):
2120        # hack to prevent conditional import fallback functions from
2121        # being cdpef-ed (global Python variables currently conflict
2122        # with imports)
2123        if self.scope.is_module_scope:
2124            for name, _ in node.items:
2125                self.imported_names.add(name)
2126        return node
2127
2128    def visit_ExprNode(self, node):
2129        # ignore lambdas and everything else that appears in expressions
2130        return node
2131
2132
2133class RemoveUnreachableCode(CythonTransform):
2134    def visit_StatListNode(self, node):
2135        if not self.current_directives['remove_unreachable']:
2136            return node
2137        self.visitchildren(node)
2138        for idx, stat in enumerate(node.stats):
2139            idx += 1
2140            if stat.is_terminator:
2141                if idx < len(node.stats):
2142                    if self.current_directives['warn.unreachable']:
2143                        warning(node.stats[idx].pos, "Unreachable code", 2)
2144                    node.stats = node.stats[:idx]
2145                node.is_terminator = True
2146                break
2147        return node
2148
2149    def visit_IfClauseNode(self, node):
2150        self.visitchildren(node)
2151        if node.body.is_terminator:
2152            node.is_terminator = True
2153        return node
2154
2155    def visit_IfStatNode(self, node):
2156        self.visitchildren(node)
2157        if node.else_clause and node.else_clause.is_terminator:
2158            for clause in node.if_clauses:
2159                if not clause.is_terminator:
2160                    break
2161            else:
2162                node.is_terminator = True
2163        return node
2164
2165    def visit_TryExceptStatNode(self, node):
2166        self.visitchildren(node)
2167        if node.body.is_terminator and node.else_clause:
2168            if self.current_directives['warn.unreachable']:
2169                warning(node.else_clause.pos, "Unreachable code", 2)
2170            node.else_clause = None
2171        return node
2172
2173
2174class YieldNodeCollector(TreeVisitor):
2175
2176    def __init__(self):
2177        super(YieldNodeCollector, self).__init__()
2178        self.yields = []
2179        self.returns = []
2180        self.has_return_value = False
2181
2182    def visit_Node(self, node):
2183        self.visitchildren(node)
2184
2185    def visit_YieldExprNode(self, node):
2186        self.yields.append(node)
2187        self.visitchildren(node)
2188
2189    def visit_ReturnStatNode(self, node):
2190        self.visitchildren(node)
2191        if node.value:
2192            self.has_return_value = True
2193        self.returns.append(node)
2194
2195    def visit_ClassDefNode(self, node):
2196        pass
2197
2198    def visit_FuncDefNode(self, node):
2199        pass
2200
2201    def visit_LambdaNode(self, node):
2202        pass
2203
2204    def visit_GeneratorExpressionNode(self, node):
2205        pass
2206
2207
2208class MarkClosureVisitor(CythonTransform):
2209
2210    def visit_ModuleNode(self, node):
2211        self.needs_closure = False
2212        self.visitchildren(node)
2213        return node
2214
2215    def visit_FuncDefNode(self, node):
2216        self.needs_closure = False
2217        self.visitchildren(node)
2218        node.needs_closure = self.needs_closure
2219        self.needs_closure = True
2220
2221        collector = YieldNodeCollector()
2222        collector.visitchildren(node)
2223
2224        if collector.yields:
2225            if isinstance(node, Nodes.CFuncDefNode):
2226                # Will report error later
2227                return node
2228            for i, yield_expr in enumerate(collector.yields):
2229                yield_expr.label_num = i + 1  # no enumerate start arg in Py2.4
2230            for retnode in collector.returns:
2231                retnode.in_generator = True
2232
2233            gbody = Nodes.GeneratorBodyDefNode(
2234                pos=node.pos, name=node.name, body=node.body)
2235            generator = Nodes.GeneratorDefNode(
2236                pos=node.pos, name=node.name, args=node.args,
2237                star_arg=node.star_arg, starstar_arg=node.starstar_arg,
2238                doc=node.doc, decorators=node.decorators,
2239                gbody=gbody, lambda_name=node.lambda_name)
2240            return generator
2241        return node
2242
2243    def visit_CFuncDefNode(self, node):
2244        self.visit_FuncDefNode(node)
2245        if node.needs_closure:
2246            error(node.pos, "closures inside cdef functions not yet supported")
2247        return node
2248
2249    def visit_LambdaNode(self, node):
2250        self.needs_closure = False
2251        self.visitchildren(node)
2252        node.needs_closure = self.needs_closure
2253        self.needs_closure = True
2254        return node
2255
2256    def visit_ClassDefNode(self, node):
2257        self.visitchildren(node)
2258        self.needs_closure = True
2259        return node
2260
2261class CreateClosureClasses(CythonTransform):
2262    # Output closure classes in module scope for all functions
2263    # that really need it.
2264
2265    def __init__(self, context):
2266        super(CreateClosureClasses, self).__init__(context)
2267        self.path = []
2268        self.in_lambda = False
2269
2270    def visit_ModuleNode(self, node):
2271        self.module_scope = node.scope
2272        self.visitchildren(node)
2273        return node
2274
2275    def find_entries_used_in_closures(self, node):
2276        from_closure = []
2277        in_closure = []
2278        for name, entry in node.local_scope.entries.items():
2279            if entry.from_closure:
2280                from_closure.append((name, entry))
2281            elif entry.in_closure:
2282                in_closure.append((name, entry))
2283        return from_closure, in_closure
2284
2285    def create_class_from_scope(self, node, target_module_scope, inner_node=None):
2286        # move local variables into closure
2287        if node.is_generator:
2288            for entry in node.local_scope.entries.values():
2289                if not entry.from_closure:
2290                    entry.in_closure = True
2291
2292        from_closure, in_closure = self.find_entries_used_in_closures(node)
2293        in_closure.sort()
2294
2295        # Now from the begining
2296        node.needs_closure = False
2297        node.needs_outer_scope = False
2298
2299        func_scope = node.local_scope
2300        cscope = node.entry.scope
2301        while cscope.is_py_class_scope or cscope.is_c_class_scope:
2302            cscope = cscope.outer_scope
2303
2304        if not from_closure and (self.path or inner_node):
2305            if not inner_node:
2306                if not node.py_cfunc_node:
2307                    raise InternalError("DefNode does not have assignment node")
2308                inner_node = node.py_cfunc_node
2309            inner_node.needs_self_code = False
2310            node.needs_outer_scope = False
2311
2312        if node.is_generator:
2313            pass
2314        elif not in_closure and not from_closure:
2315            return
2316        elif not in_closure:
2317            func_scope.is_passthrough = True
2318            func_scope.scope_class = cscope.scope_class
2319            node.needs_outer_scope = True
2320            return
2321
2322        as_name = '%s_%s' % (
2323            target_module_scope.next_id(Naming.closure_class_prefix),
2324            node.entry.cname)
2325
2326        entry = target_module_scope.declare_c_class(
2327            name=as_name, pos=node.pos, defining=True,
2328            implementing=True)
2329        entry.type.is_final_type = True
2330
2331        func_scope.scope_class = entry
2332        class_scope = entry.type.scope
2333        class_scope.is_internal = True
2334        if Options.closure_freelist_size:
2335            class_scope.directives['freelist'] = Options.closure_freelist_size
2336
2337        if from_closure:
2338            assert cscope.is_closure_scope
2339            class_scope.declare_var(pos=node.pos,
2340                                    name=Naming.outer_scope_cname,
2341                                    cname=Naming.outer_scope_cname,
2342                                    type=cscope.scope_class.type,
2343                                    is_cdef=True)
2344            node.needs_outer_scope = True
2345        for name, entry in in_closure:
2346            closure_entry = class_scope.declare_var(pos=entry.pos,
2347                                    name=entry.name,
2348                                    cname=entry.cname,
2349                                    type=entry.type,
2350                                    is_cdef=True)
2351            if entry.is_declared_generic:
2352                closure_entry.is_declared_generic = 1
2353        node.needs_closure = True
2354        # Do it here because other classes are already checked
2355        target_module_scope.check_c_class(func_scope.scope_class)
2356
2357    def visit_LambdaNode(self, node):
2358        if not isinstance(node.def_node, Nodes.DefNode):
2359            # fused function, an error has been previously issued
2360            return node
2361
2362        was_in_lambda = self.in_lambda
2363        self.in_lambda = True
2364        self.create_class_from_scope(node.def_node, self.module_scope, node)
2365        self.visitchildren(node)
2366        self.in_lambda = was_in_lambda
2367        return node
2368
2369    def visit_FuncDefNode(self, node):
2370        if self.in_lambda:
2371            self.visitchildren(node)
2372            return node
2373        if node.needs_closure or self.path:
2374            self.create_class_from_scope(node, self.module_scope)
2375            self.path.append(node)
2376            self.visitchildren(node)
2377            self.path.pop()
2378        return node
2379
2380    def visit_GeneratorBodyDefNode(self, node):
2381        self.visitchildren(node)
2382        return node
2383
2384    def visit_CFuncDefNode(self, node):
2385        self.visitchildren(node)
2386        return node
2387
2388
2389class GilCheck(VisitorTransform):
2390    """
2391    Call `node.gil_check(env)` on each node to make sure we hold the
2392    GIL when we need it.  Raise an error when on Python operations
2393    inside a `nogil` environment.
2394
2395    Additionally, raise exceptions for closely nested with gil or with nogil
2396    statements. The latter would abort Python.
2397    """
2398
2399    def __call__(self, root):
2400        self.env_stack = [root.scope]
2401        self.nogil = False
2402
2403        # True for 'cdef func() nogil:' functions, as the GIL may be held while
2404        # calling this function (thus contained 'nogil' blocks may be valid).
2405        self.nogil_declarator_only = False
2406        return super(GilCheck, self).__call__(root)
2407
2408    def visit_FuncDefNode(self, node):
2409        self.env_stack.append(node.local_scope)
2410        was_nogil = self.nogil
2411        self.nogil = node.local_scope.nogil
2412
2413        if self.nogil:
2414            self.nogil_declarator_only = True
2415
2416        if self.nogil and node.nogil_check:
2417            node.nogil_check(node.local_scope)
2418
2419        self.visitchildren(node)
2420
2421        # This cannot be nested, so it doesn't need backup/restore
2422        self.nogil_declarator_only = False
2423
2424        self.env_stack.pop()
2425        self.nogil = was_nogil
2426        return node
2427
2428    def visit_GILStatNode(self, node):
2429        if self.nogil and node.nogil_check:
2430            node.nogil_check()
2431
2432        was_nogil = self.nogil
2433        self.nogil = (node.state == 'nogil')
2434
2435        if was_nogil == self.nogil and not self.nogil_declarator_only:
2436            if not was_nogil:
2437                error(node.pos, "Trying to acquire the GIL while it is "
2438                                "already held.")
2439            else:
2440                error(node.pos, "Trying to release the GIL while it was "
2441                                "previously released.")
2442
2443        if isinstance(node.finally_clause, Nodes.StatListNode):
2444            # The finally clause of the GILStatNode is a GILExitNode,
2445            # which is wrapped in a StatListNode. Just unpack that.
2446            node.finally_clause, = node.finally_clause.stats
2447
2448        self.visitchildren(node)
2449        self.nogil = was_nogil
2450        return node
2451
2452    def visit_ParallelRangeNode(self, node):
2453        if node.nogil:
2454            node.nogil = False
2455            node = Nodes.GILStatNode(node.pos, state='nogil', body=node)
2456            return self.visit_GILStatNode(node)
2457
2458        if not self.nogil:
2459            error(node.pos, "prange() can only be used without the GIL")
2460            # Forget about any GIL-related errors that may occur in the body
2461            return None
2462
2463        node.nogil_check(self.env_stack[-1])
2464        self.visitchildren(node)
2465        return node
2466
2467    def visit_ParallelWithBlockNode(self, node):
2468        if not self.nogil:
2469            error(node.pos, "The parallel section may only be used without "
2470                            "the GIL")
2471            return None
2472
2473        if node.nogil_check:
2474            # It does not currently implement this, but test for it anyway to
2475            # avoid potential future surprises
2476            node.nogil_check(self.env_stack[-1])
2477
2478        self.visitchildren(node)
2479        return node
2480
2481    def visit_TryFinallyStatNode(self, node):
2482        """
2483        Take care of try/finally statements in nogil code sections.
2484        """
2485        if not self.nogil or isinstance(node, Nodes.GILStatNode):
2486            return self.visit_Node(node)
2487
2488        node.nogil_check = None
2489        node.is_try_finally_in_nogil = True
2490        self.visitchildren(node)
2491        return node
2492
2493    def visit_Node(self, node):
2494        if self.env_stack and self.nogil and node.nogil_check:
2495            node.nogil_check(self.env_stack[-1])
2496        self.visitchildren(node)
2497        node.in_nogil_context = self.nogil
2498        return node
2499
2500
2501class TransformBuiltinMethods(EnvTransform):
2502
2503    def visit_SingleAssignmentNode(self, node):
2504        if node.declaration_only:
2505            return None
2506        else:
2507            self.visitchildren(node)
2508            return node
2509
2510    def visit_AttributeNode(self, node):
2511        self.visitchildren(node)
2512        return self.visit_cython_attribute(node)
2513
2514    def visit_NameNode(self, node):
2515        return self.visit_cython_attribute(node)
2516
2517    def visit_cython_attribute(self, node):
2518        attribute = node.as_cython_attribute()
2519        if attribute:
2520            if attribute == u'compiled':
2521                node = ExprNodes.BoolNode(node.pos, value=True)
2522            elif attribute == u'__version__':
2523                import Cython
2524                node = ExprNodes.StringNode(node.pos, value=EncodedString(Cython.__version__))
2525            elif attribute == u'NULL':
2526                node = ExprNodes.NullNode(node.pos)
2527            elif attribute in (u'set', u'frozenset'):
2528                node = ExprNodes.NameNode(node.pos, name=EncodedString(attribute),
2529                                          entry=self.current_env().builtin_scope().lookup_here(attribute))
2530            elif PyrexTypes.parse_basic_type(attribute):
2531                pass
2532            elif self.context.cython_scope.lookup_qualified_name(attribute):
2533                pass
2534            else:
2535                error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
2536        return node
2537
2538    def visit_ExecStatNode(self, node):
2539        lenv = self.current_env()
2540        self.visitchildren(node)
2541        if len(node.args) == 1:
2542            node.args.append(ExprNodes.GlobalsExprNode(node.pos))
2543            if not lenv.is_module_scope:
2544                node.args.append(
2545                    ExprNodes.LocalsExprNode(
2546                        node.pos, self.current_scope_node(), lenv))
2547        return node
2548
2549    def _inject_locals(self, node, func_name):
2550        # locals()/dir()/vars() builtins
2551        lenv = self.current_env()
2552        entry = lenv.lookup_here(func_name)
2553        if entry:
2554            # not the builtin
2555            return node
2556        pos = node.pos
2557        if func_name in ('locals', 'vars'):
2558            if func_name == 'locals' and len(node.args) > 0:
2559                error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d"
2560                      % len(node.args))
2561                return node
2562            elif func_name == 'vars':
2563                if len(node.args) > 1:
2564                    error(self.pos, "Builtin 'vars()' called with wrong number of args, expected 0-1, got %d"
2565                          % len(node.args))
2566                if len(node.args) > 0:
2567                    return node # nothing to do
2568            return ExprNodes.LocalsExprNode(pos, self.current_scope_node(), lenv)
2569        else: # dir()
2570            if len(node.args) > 1:
2571                error(self.pos, "Builtin 'dir()' called with wrong number of args, expected 0-1, got %d"
2572                      % len(node.args))
2573            if len(node.args) > 0:
2574                # optimised in Builtin.py
2575                return node
2576            if lenv.is_py_class_scope or lenv.is_module_scope:
2577                if lenv.is_py_class_scope:
2578                    pyclass = self.current_scope_node()
2579                    locals_dict = ExprNodes.CloneNode(pyclass.dict)
2580                else:
2581                    locals_dict = ExprNodes.GlobalsExprNode(pos)
2582                return ExprNodes.SortedDictKeysNode(locals_dict)
2583            local_names = [ var.name for var in lenv.entries.values() if var.name ]
2584            items = [ ExprNodes.IdentifierStringNode(pos, value=var)
2585                      for var in local_names ]
2586            return ExprNodes.ListNode(pos, args=items)
2587
2588    def visit_PrimaryCmpNode(self, node):
2589        # special case: for in/not-in test, we do not need to sort locals()
2590        self.visitchildren(node)
2591        if node.operator in 'not_in':  # in/not_in
2592            if isinstance(node.operand2, ExprNodes.SortedDictKeysNode):
2593                arg = node.operand2.arg
2594                if isinstance(arg, ExprNodes.NoneCheckNode):
2595                    arg = arg.arg
2596                node.operand2 = arg
2597        return node
2598
2599    def visit_CascadedCmpNode(self, node):
2600        return self.visit_PrimaryCmpNode(node)
2601
2602    def _inject_eval(self, node, func_name):
2603        lenv = self.current_env()
2604        entry = lenv.lookup_here(func_name)
2605        if entry or len(node.args) != 1:
2606            return node
2607        # Inject globals and locals
2608        node.args.append(ExprNodes.GlobalsExprNode(node.pos))
2609        if not lenv.is_module_scope:
2610            node.args.append(
2611                ExprNodes.LocalsExprNode(
2612                    node.pos, self.current_scope_node(), lenv))
2613        return node
2614
2615    def _inject_super(self, node, func_name):
2616        lenv = self.current_env()
2617        entry = lenv.lookup_here(func_name)
2618        if entry or node.args:
2619            return node
2620        # Inject no-args super
2621        def_node = self.current_scope_node()
2622        if (not isinstance(def_node, Nodes.DefNode) or not def_node.args or
2623            len(self.env_stack) < 2):
2624            return node
2625        class_node, class_scope = self.env_stack[-2]
2626        if class_scope.is_py_class_scope:
2627            def_node.requires_classobj = True
2628            class_node.class_cell.is_active = True
2629            node.args = [
2630                ExprNodes.ClassCellNode(
2631                    node.pos, is_generator=def_node.is_generator),
2632                ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
2633                ]
2634        elif class_scope.is_c_class_scope:
2635            node.args = [
2636                ExprNodes.NameNode(
2637                    node.pos, name=class_node.scope.name,
2638                    entry=class_node.entry),
2639                ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
2640                ]
2641        return node
2642
2643    def visit_SimpleCallNode(self, node):
2644        # cython.foo
2645        function = node.function.as_cython_attribute()
2646        if function:
2647            if function in InterpretCompilerDirectives.unop_method_nodes:
2648                if len(node.args) != 1:
2649                    error(node.function.pos, u"%s() takes exactly one argument" % function)
2650                else:
2651                    node = InterpretCompilerDirectives.unop_method_nodes[function](node.function.pos, operand=node.args[0])
2652            elif function in InterpretCompilerDirectives.binop_method_nodes:
2653                if len(node.args) != 2:
2654                    error(node.function.pos, u"%s() takes exactly two arguments" % function)
2655                else:
2656                    node = InterpretCompilerDirectives.binop_method_nodes[function](node.function.pos, operand1=node.args[0], operand2=node.args[1])
2657            elif function == u'cast':
2658                if len(node.args) != 2:
2659                    error(node.function.pos, u"cast() takes exactly two arguments")
2660                else:
2661                    type = node.args[0].analyse_as_type(self.current_env())
2662                    if type:
2663                        node = ExprNodes.TypecastNode(node.function.pos, type=type, operand=node.args[1])
2664                    else:
2665                        error(node.args[0].pos, "Not a type")
2666            elif function == u'sizeof':
2667                if len(node.args) != 1:
2668                    error(node.function.pos, u"sizeof() takes exactly one argument")
2669                else:
2670                    type = node.args[0].analyse_as_type(self.current_env())
2671                    if type:
2672                        node = ExprNodes.SizeofTypeNode(node.function.pos, arg_type=type)
2673                    else:
2674                        node = ExprNodes.SizeofVarNode(node.function.pos, operand=node.args[0])
2675            elif function == 'cmod':
2676                if len(node.args) != 2:
2677                    error(node.function.pos, u"cmod() takes exactly two arguments")
2678                else:
2679                    node = ExprNodes.binop_node(node.function.pos, '%', node.args[0], node.args[1])
2680                    node.cdivision = True
2681            elif function == 'cdiv':
2682                if len(node.args) != 2:
2683                    error(node.function.pos, u"cdiv() takes exactly two arguments")
2684                else:
2685                    node = ExprNodes.binop_node(node.function.pos, '/', node.args[0], node.args[1])
2686                    node.cdivision = True
2687            elif function == u'set':
2688                node.function = ExprNodes.NameNode(node.pos, name=EncodedString('set'))
2689            elif self.context.cython_scope.lookup_qualified_name(function):
2690                pass
2691            else:
2692                error(node.function.pos,
2693                      u"'%s' not a valid cython language construct" % function)
2694
2695        self.visitchildren(node)
2696
2697        if isinstance(node, ExprNodes.SimpleCallNode) and node.function.is_name:
2698            func_name = node.function.name
2699            if func_name in ('dir', 'locals', 'vars'):
2700                return self._inject_locals(node, func_name)
2701            if func_name == 'eval':
2702                return self._inject_eval(node, func_name)
2703            if func_name == 'super':
2704                return self._inject_super(node, func_name)
2705        return node
2706
2707
2708class ReplaceFusedTypeChecks(VisitorTransform):
2709    """
2710    This is not a transform in the pipeline. It is invoked on the specific
2711    versions of a cdef function with fused argument types. It filters out any
2712    type branches that don't match. e.g.
2713
2714        if fused_t is mytype:
2715            ...
2716        elif fused_t in other_fused_type:
2717            ...
2718    """
2719    def __init__(self, local_scope):
2720        super(ReplaceFusedTypeChecks, self).__init__()
2721        self.local_scope = local_scope
2722        # defer the import until now to avoid circular import time dependencies
2723        from Cython.Compiler import Optimize
2724        self.transform = Optimize.ConstantFolding(reevaluate=True)
2725
2726    def visit_IfStatNode(self, node):
2727        """
2728        Filters out any if clauses with false compile time type check
2729        expression.
2730        """
2731        self.visitchildren(node)
2732        return self.transform(node)
2733
2734    def visit_PrimaryCmpNode(self, node):
2735        type1 = node.operand1.analyse_as_type(self.local_scope)
2736        type2 = node.operand2.analyse_as_type(self.local_scope)
2737
2738        if type1 and type2:
2739            false_node = ExprNodes.BoolNode(node.pos, value=False)
2740            true_node = ExprNodes.BoolNode(node.pos, value=True)
2741
2742            type1 = self.specialize_type(type1, node.operand1.pos)
2743            op = node.operator
2744
2745            if op in ('is', 'is_not', '==', '!='):
2746                type2 = self.specialize_type(type2, node.operand2.pos)
2747
2748                is_same = type1.same_as(type2)
2749                eq = op in ('is', '==')
2750
2751                if (is_same and eq) or (not is_same and not eq):
2752                    return true_node
2753
2754            elif op in ('in', 'not_in'):
2755                # We have to do an instance check directly, as operand2
2756                # needs to be a fused type and not a type with a subtype
2757                # that is fused. First unpack the typedef
2758                if isinstance(type2, PyrexTypes.CTypedefType):
2759                    type2 = type2.typedef_base_type
2760
2761                if type1.is_fused:
2762                    error(node.operand1.pos, "Type is fused")
2763                elif not type2.is_fused:
2764                    error(node.operand2.pos,
2765                          "Can only use 'in' or 'not in' on a fused type")
2766                else:
2767                    types = PyrexTypes.get_specialized_types(type2)
2768
2769                    for specialized_type in types:
2770                        if type1.same_as(specialized_type):
2771                            if op == 'in':
2772                                return true_node
2773                            else:
2774                                return false_node
2775
2776                    if op == 'not_in':
2777                        return true_node
2778
2779            return false_node
2780
2781        return node
2782
2783    def specialize_type(self, type, pos):
2784        try:
2785            return type.specialize(self.local_scope.fused_to_specific)
2786        except KeyError:
2787            error(pos, "Type is not specific")
2788            return type
2789
2790    def visit_Node(self, node):
2791        self.visitchildren(node)
2792        return node
2793
2794
2795class DebugTransform(CythonTransform):
2796    """
2797    Write debug information for this Cython module.
2798    """
2799
2800    def __init__(self, context, options, result):
2801        super(DebugTransform, self).__init__(context)
2802        self.visited = set()
2803        # our treebuilder and debug output writer
2804        # (see Cython.Debugger.debug_output.CythonDebugWriter)
2805        self.tb = self.context.gdb_debug_outputwriter
2806        #self.c_output_file = options.output_file
2807        self.c_output_file = result.c_file
2808
2809        # Closure support, basically treat nested functions as if the AST were
2810        # never nested
2811        self.nested_funcdefs = []
2812
2813        # tells visit_NameNode whether it should register step-into functions
2814        self.register_stepinto = False
2815
2816    def visit_ModuleNode(self, node):
2817        self.tb.module_name = node.full_module_name
2818        attrs = dict(
2819            module_name=node.full_module_name,
2820            filename=node.pos[0].filename,
2821            c_filename=self.c_output_file)
2822
2823        self.tb.start('Module', attrs)
2824
2825        # serialize functions
2826        self.tb.start('Functions')
2827        # First, serialize functions normally...
2828        self.visitchildren(node)
2829
2830        # ... then, serialize nested functions
2831        for nested_funcdef in self.nested_funcdefs:
2832            self.visit_FuncDefNode(nested_funcdef)
2833
2834        self.register_stepinto = True
2835        self.serialize_modulenode_as_function(node)
2836        self.register_stepinto = False
2837        self.tb.end('Functions')
2838
2839        # 2.3 compatibility. Serialize global variables
2840        self.tb.start('Globals')
2841        entries = {}
2842
2843        for k, v in node.scope.entries.iteritems():
2844            if (v.qualified_name not in self.visited and not
2845                v.name.startswith('__pyx_') and not
2846                v.type.is_cfunction and not
2847                v.type.is_extension_type):
2848                entries[k]= v
2849
2850        self.serialize_local_variables(entries)
2851        self.tb.end('Globals')
2852        # self.tb.end('Module') # end Module after the line number mapping in
2853        # Cython.Compiler.ModuleNode.ModuleNode._serialize_lineno_map
2854        return node
2855
2856    def visit_FuncDefNode(self, node):
2857        self.visited.add(node.local_scope.qualified_name)
2858
2859        if getattr(node, 'is_wrapper', False):
2860            return node
2861
2862        if self.register_stepinto:
2863            self.nested_funcdefs.append(node)
2864            return node
2865
2866        # node.entry.visibility = 'extern'
2867        if node.py_func is None:
2868            pf_cname = ''
2869        else:
2870            pf_cname = node.py_func.entry.func_cname
2871
2872        attrs = dict(
2873            name=node.entry.name or getattr(node, 'name', '<unknown>'),
2874            cname=node.entry.func_cname,
2875            pf_cname=pf_cname,
2876            qualified_name=node.local_scope.qualified_name,
2877            lineno=str(node.pos[1]))
2878
2879        self.tb.start('Function', attrs=attrs)
2880
2881        self.tb.start('Locals')
2882        self.serialize_local_variables(node.local_scope.entries)
2883        self.tb.end('Locals')
2884
2885        self.tb.start('Arguments')
2886        for arg in node.local_scope.arg_entries:
2887            self.tb.start(arg.name)
2888            self.tb.end(arg.name)
2889        self.tb.end('Arguments')
2890
2891        self.tb.start('StepIntoFunctions')
2892        self.register_stepinto = True
2893        self.visitchildren(node)
2894        self.register_stepinto = False
2895        self.tb.end('StepIntoFunctions')
2896        self.tb.end('Function')
2897
2898        return node
2899
2900    def visit_NameNode(self, node):
2901        if (self.register_stepinto and
2902            node.type.is_cfunction and
2903            getattr(node, 'is_called', False) and
2904            node.entry.func_cname is not None):
2905            # don't check node.entry.in_cinclude, as 'cdef extern: ...'
2906            # declared functions are not 'in_cinclude'.
2907            # This means we will list called 'cdef' functions as
2908            # "step into functions", but this is not an issue as they will be
2909            # recognized as Cython functions anyway.
2910            attrs = dict(name=node.entry.func_cname)
2911            self.tb.start('StepIntoFunction', attrs=attrs)
2912            self.tb.end('StepIntoFunction')
2913
2914        self.visitchildren(node)
2915        return node
2916
2917    def serialize_modulenode_as_function(self, node):
2918        """
2919        Serialize the module-level code as a function so the debugger will know
2920        it's a "relevant frame" and it will know where to set the breakpoint
2921        for 'break modulename'.
2922        """
2923        name = node.full_module_name.rpartition('.')[-1]
2924
2925        cname_py2 = 'init' + name
2926        cname_py3 = 'PyInit_' + name
2927
2928        py2_attrs = dict(
2929            name=name,
2930            cname=cname_py2,
2931            pf_cname='',
2932            # Ignore the qualified_name, breakpoints should be set using
2933            # `cy break modulename:lineno` for module-level breakpoints.
2934            qualified_name='',
2935            lineno='1',
2936            is_initmodule_function="True",
2937        )
2938
2939        py3_attrs = dict(py2_attrs, cname=cname_py3)
2940
2941        self._serialize_modulenode_as_function(node, py2_attrs)
2942        self._serialize_modulenode_as_function(node, py3_attrs)
2943
2944    def _serialize_modulenode_as_function(self, node, attrs):
2945        self.tb.start('Function', attrs=attrs)
2946
2947        self.tb.start('Locals')
2948        self.serialize_local_variables(node.scope.entries)
2949        self.tb.end('Locals')
2950
2951        self.tb.start('Arguments')
2952        self.tb.end('Arguments')
2953
2954        self.tb.start('StepIntoFunctions')
2955        self.register_stepinto = True
2956        self.visitchildren(node)
2957        self.register_stepinto = False
2958        self.tb.end('StepIntoFunctions')
2959
2960        self.tb.end('Function')
2961
2962    def serialize_local_variables(self, entries):
2963        for entry in entries.values():
2964            if not entry.cname:
2965                # not a local variable
2966                continue
2967            if entry.type.is_pyobject:
2968                vartype = 'PythonObject'
2969            else:
2970                vartype = 'CObject'
2971
2972            if entry.from_closure:
2973                # We're dealing with a closure where a variable from an outer
2974                # scope is accessed, get it from the scope object.
2975                cname = '%s->%s' % (Naming.cur_scope_cname,
2976                                    entry.outer_entry.cname)
2977
2978                qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
2979                                      entry.scope.name,
2980                                      entry.name)
2981            elif entry.in_closure:
2982                cname = '%s->%s' % (Naming.cur_scope_cname,
2983                                    entry.cname)
2984                qname = entry.qualified_name
2985            else:
2986                cname = entry.cname
2987                qname = entry.qualified_name
2988
2989            if not entry.pos:
2990                # this happens for variables that are not in the user's code,
2991                # e.g. for the global __builtins__, __doc__, etc. We can just
2992                # set the lineno to 0 for those.
2993                lineno = '0'
2994            else:
2995                lineno = str(entry.pos[1])
2996
2997            attrs = dict(
2998                name=entry.name,
2999                cname=cname,
3000                qualified_name=qname,
3001                type=vartype,
3002                lineno=lineno)
3003
3004            self.tb.start('LocalVar', attrs)
3005            self.tb.end('LocalVar')
3006