Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / cython / src / Cython / Compiler / ParseTreeTransforms.py
1 import cython
2 cython.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
7 import PyrexTypes
8 import Naming
9 import ExprNodes
10 import Nodes
11 import Options
12 import Builtin
13
14 from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
15 from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
16 from Cython.Compiler.UtilNodes import LetNode, LetRefNode, ResultRefNode
17 from Cython.Compiler.TreeFragment import TreeFragment
18 from Cython.Compiler.StringEncoding import EncodedString
19 from Cython.Compiler.Errors import error, warning, CompileError, InternalError
20 from Cython.Compiler.Code import UtilityCode
21
22 import copy
23
24
25 class 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
40 class 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
66 class 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
142 class PostParseError(CompileError): pass
143
144 # error strings checked by unit tests, so define them
145 ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
146 ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
147 ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
148 class 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
362 def 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
408 def 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
441 def 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
452 def 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
521 def 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
557 class 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
613 class 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
1035 class 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
1209 class 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
1272 class 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
1309 class 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
1356 class 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
1394 class AnalyseDeclarationsTransform(EnvTransform):
1395
1396     basic_property = TreeFragment(u"""
1397 property 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"""
1404 property 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"""
1413 property NAME:
1414     def __get__(self):
1415         return ATTR
1416     """, level='c_class', pipeline=[NormalizeTree(None)])
1417
1418     struct_or_union_wrapper = TreeFragment(u"""
1419 cdef 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"""
1434 if 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
1825 class 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
1887 class 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
1930 class 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
1952 class 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
2011 class 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
2065 class 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
2133 class 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
2174 class 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
2208 class 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
2261 class 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
2389 class 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
2501 class 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
2708 class 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
2795 class 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')