1 from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
2 from Cython.Compiler.Visitor import CythonTransform, EnvTransform
3 from Cython.Compiler.ModuleNode import ModuleNode
4 from Cython.Compiler.Nodes import *
5 from Cython.Compiler.ExprNodes import *
6 from Cython.Compiler.UtilNodes import *
7 from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
8 from Cython.Compiler.StringEncoding import EncodedString
9 from Cython.Compiler.Errors import error, CompileError
13 from sets import Set as set
17 class NameNodeCollector(TreeVisitor):
18 """Collect all NameNodes of a (sub-)tree in the ``name_nodes``
22 super(NameNodeCollector, self).__init__()
25 visit_Node = TreeVisitor.visitchildren
27 def visit_NameNode(self, node):
28 self.name_nodes.append(node)
31 class SkipDeclarations(object):
33 Variable and function declarations can often have a deep tree structure,
34 and yet most transformations don't need to descend to this depth.
36 Declaration nodes are removed after AnalyseDeclarationsTransform, so there
37 is no need to use this for transformations after that point.
39 def visit_CTypeDefNode(self, node):
42 def visit_CVarDefNode(self, node):
45 def visit_CDeclaratorNode(self, node):
48 def visit_CBaseTypeNode(self, node):
51 def visit_CEnumDefNode(self, node):
54 def visit_CStructOrUnionDefNode(self, node):
58 class NormalizeTree(CythonTransform):
60 This transform fixes up a few things after parsing
61 in order to make the parse tree more suitable for
64 a) After parsing, blocks with only one statement will
65 be represented by that statement, not by a StatListNode.
66 When doing transforms this is annoying and inconsistent,
67 as one cannot in general remove a statement in a consistent
68 way and so on. This transform wraps any single statements
69 in a StatListNode containing a single statement.
71 b) The PassStatNode is a noop and serves no purpose beyond
72 plugging such one-statement blocks; i.e., once parsed a
73 ` "pass" can just as well be represented using an empty
74 StatListNode. This means less special cases to worry about
75 in subsequent transforms (one always checks to see if a
76 StatListNode has no children to see if the block is empty).
79 def __init__(self, context):
80 super(NormalizeTree, self).__init__(context)
81 self.is_in_statlist = False
82 self.is_in_expr = False
84 def visit_ExprNode(self, node):
85 stacktmp = self.is_in_expr
86 self.is_in_expr = True
87 self.visitchildren(node)
88 self.is_in_expr = stacktmp
91 def visit_StatNode(self, node, is_listcontainer=False):
92 stacktmp = self.is_in_statlist
93 self.is_in_statlist = is_listcontainer
94 self.visitchildren(node)
95 self.is_in_statlist = stacktmp
96 if not self.is_in_statlist and not self.is_in_expr:
97 return StatListNode(pos=node.pos, stats=[node])
101 def visit_StatListNode(self, node):
102 self.is_in_statlist = True
103 self.visitchildren(node)
104 self.is_in_statlist = False
107 def visit_ParallelAssignmentNode(self, node):
108 return self.visit_StatNode(node, True)
110 def visit_CEnumDefNode(self, node):
111 return self.visit_StatNode(node, True)
113 def visit_CStructOrUnionDefNode(self, node):
114 return self.visit_StatNode(node, True)
116 # Eliminate PassStatNode
117 def visit_PassStatNode(self, node):
118 if not self.is_in_statlist:
119 return StatListNode(pos=node.pos, stats=[])
123 def visit_CDeclaratorNode(self, node):
127 class PostParseError(CompileError): pass
129 # error strings checked by unit tests, so define them
130 ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
131 ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
132 ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
133 class PostParse(CythonTransform):
135 Basic interpretation of the parse tree, as well as validity
136 checking that can be done on a very basic level on the parse
137 tree (while still not being a problem with the basic syntax,
141 - Default values to cdef assignments are turned into single
142 assignments following the declaration (everywhere but in class
143 bodies, where they raise a compile error)
145 - Interpret some node structures into Python runtime values.
146 Some nodes take compile-time arguments (currently:
147 TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
148 which should be interpreted. This happens in a general way
149 and other steps should be taken to ensure validity.
151 Type arguments cannot be interpreted in this way.
153 - For __cythonbufferdefaults__ the arguments are checked for
156 TemplatedTypeNode has its directives interpreted:
157 Any first positional argument goes into the "dtype" attribute,
158 any "ndim" keyword argument goes into the "ndim" attribute and
159 so on. Also it is checked that the directive combination is valid.
160 - __cythonbufferdefaults__ attributes are parsed and put into the
163 Note: Currently Parsing.py does a lot of interpretation and
164 reorganization that can be refactored into this transform
165 if a more pure Abstract Syntax Tree is wanted.
169 scope_type = None # can be either of 'module', 'function', 'class'
171 def __init__(self, context):
172 super(PostParse, self).__init__(context)
173 self.specialattribute_handlers = {
174 '__cythonbufferdefaults__' : self.handle_bufferdefaults
177 def visit_ModuleNode(self, node):
178 self.scope_type = 'module'
179 self.scope_node = node
180 self.lambda_counter = 1
181 self.visitchildren(node)
184 def visit_scope(self, node, scope_type):
185 prev = self.scope_type, self.scope_node
186 self.scope_type = scope_type
187 self.scope_node = node
188 self.visitchildren(node)
189 self.scope_type, self.scope_node = prev
192 def visit_ClassDefNode(self, node):
193 return self.visit_scope(node, 'class')
195 def visit_FuncDefNode(self, node):
196 return self.visit_scope(node, 'function')
198 def visit_CStructOrUnionDefNode(self, node):
199 return self.visit_scope(node, 'struct')
201 def visit_LambdaNode(self, node):
202 # unpack a lambda expression into the corresponding DefNode
203 if self.scope_type != 'function':
205 "lambda functions are currently only supported in functions")
206 lambda_id = self.lambda_counter
207 self.lambda_counter += 1
208 node.lambda_name = EncodedString(u'lambda%d' % lambda_id)
210 body = Nodes.ReturnStatNode(
211 node.result_expr.pos, value = node.result_expr)
212 node.def_node = Nodes.DefNode(
213 node.pos, name=node.name, lambda_name=node.lambda_name,
214 args=node.args, star_arg=node.star_arg,
215 starstar_arg=node.starstar_arg,
217 self.visitchildren(node)
221 def handle_bufferdefaults(self, decl):
222 if not isinstance(decl.default, DictNode):
223 raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
224 self.scope_node.buffer_defaults_node = decl.default
225 self.scope_node.buffer_defaults_pos = decl.pos
227 def visit_CVarDefNode(self, node):
228 # This assumes only plain names and pointers are assignable on
229 # declaration. Also, it makes use of the fact that a cdef decl
230 # must appear before the first use, so we don't have to deal with
231 # "i = 3; cdef int i = i" and can simply move the nodes around.
233 self.visitchildren(node)
236 for decl in node.declarators:
238 while isinstance(declbase, CPtrDeclaratorNode):
239 declbase = declbase.base
240 if isinstance(declbase, CNameDeclaratorNode):
241 if declbase.default is not None:
242 if self.scope_type in ('class', 'struct'):
243 if isinstance(self.scope_node, CClassDefNode):
244 handler = self.specialattribute_handlers.get(decl.name)
246 if decl is not declbase:
247 raise PostParseError(decl.pos, ERR_INVALID_SPECIALATTR_TYPE)
249 continue # Remove declaration
250 raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
251 first_assignment = self.scope_type != 'module'
252 stats.append(SingleAssignmentNode(node.pos,
253 lhs=NameNode(node.pos, name=declbase.name),
254 rhs=declbase.default, first=first_assignment))
255 declbase.default = None
256 newdecls.append(decl)
257 node.declarators = newdecls
259 except PostParseError, e:
260 # An error in a cdef clause is ok, simply remove the declaration
261 # and try to move on to report more errors
262 self.context.nonfatal_error(e)
265 # Split parallel assignments (a,b = b,a) into separate partial
266 # assignments that are executed rhs-first using temps. This
267 # optimisation is best applied before type analysis so that known
268 # types on rhs and lhs can be matched directly.
270 def visit_SingleAssignmentNode(self, node):
271 self.visitchildren(node)
272 return self._visit_assignment_node(node, [node.lhs, node.rhs])
274 def visit_CascadedAssignmentNode(self, node):
275 self.visitchildren(node)
276 return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
278 def _visit_assignment_node(self, node, expr_list):
279 """Flatten parallel assignments into separate single
280 assignments or cascaded assignments.
282 if sum([ 1 for expr in expr_list if expr.is_sequence_constructor ]) < 2:
283 # no parallel assignments => nothing to do
287 flatten_parallel_assignments(expr_list, expr_list_list)
289 for expr_list in expr_list_list:
290 lhs_list = expr_list[:-1]
292 if len(lhs_list) == 1:
293 node = Nodes.SingleAssignmentNode(rhs.pos,
294 lhs = lhs_list[0], rhs = rhs)
296 node = Nodes.CascadedAssignmentNode(rhs.pos,
297 lhs_list = lhs_list, rhs = rhs)
302 return Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
305 def flatten_parallel_assignments(input, output):
306 # The input is a list of expression nodes, representing the LHSs
307 # and RHS of one (possibly cascaded) assignment statement. For
308 # sequence constructors, rearranges the matching parts of both
309 # sides into a list of equivalent assignments between the
310 # individual elements. This transformation is applied
311 # recursively, so that nested structures get matched as well.
313 if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
317 complete_assignments = []
319 rhs_size = len(rhs.args)
320 lhs_targets = [ [] for _ in xrange(rhs_size) ]
321 starred_assignments = []
322 for lhs in input[:-1]:
323 if not lhs.is_sequence_constructor:
325 error(lhs.pos, "starred assignment target must be in a list or tuple")
326 complete_assignments.append(lhs)
328 lhs_size = len(lhs.args)
329 starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
330 if starred_targets > 1:
331 error(lhs.pos, "more than 1 starred expression in assignment")
332 output.append([lhs,rhs])
334 elif lhs_size - starred_targets > rhs_size:
335 error(lhs.pos, "need more than %d value%s to unpack"
336 % (rhs_size, (rhs_size != 1) and 's' or ''))
337 output.append([lhs,rhs])
339 elif starred_targets == 1:
340 map_starred_assignment(lhs_targets, starred_assignments,
342 elif lhs_size < rhs_size:
343 error(lhs.pos, "too many values to unpack (expected %d, got %d)"
344 % (lhs_size, rhs_size))
345 output.append([lhs,rhs])
348 for targets, expr in zip(lhs_targets, lhs.args):
351 if complete_assignments:
352 complete_assignments.append(rhs)
353 output.append(complete_assignments)
355 # recursively flatten partial assignments
356 for cascade, rhs in zip(lhs_targets, rhs.args):
359 flatten_parallel_assignments(cascade, output)
361 # recursively flatten starred assignments
362 for cascade in starred_assignments:
363 if cascade[0].is_sequence_constructor:
364 flatten_parallel_assignments(cascade, output)
366 output.append(cascade)
368 def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
369 # Appends the fixed-position LHS targets to the target list that
370 # appear left and right of the starred argument.
372 # The starred_assignments list receives a new tuple
373 # (lhs_target, rhs_values_list) that maps the remaining arguments
374 # (those that match the starred target) to a list.
376 # left side of the starred target
377 for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
380 lhs_remaining = len(lhs_args) - i - 1
384 raise InternalError("no starred arg found when splitting starred assignment")
386 # right side of the starred target
387 for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
388 lhs_args[-lhs_remaining:])):
391 # the starred target itself, must be assigned a (potentially empty) list
392 target = lhs_args[starred].target # unpack starred node
393 starred_rhs = rhs_args[starred:]
395 starred_rhs = starred_rhs[:-lhs_remaining]
397 pos = starred_rhs[0].pos
400 starred_assignments.append([
401 target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
404 class PxdPostParse(CythonTransform, SkipDeclarations):
406 Basic interpretation/validity checking that should only be
409 A lot of this checking currently happens in the parser; but
410 what is listed below happens here.
412 - "def" functions are let through only if they fill the
413 getbuffer/releasebuffer slots
415 - cdef functions are let through only if they are on the
416 top level and are declared "inline"
418 ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'"
419 ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'"
421 def __call__(self, node):
422 self.scope_type = 'pxd'
423 return super(PxdPostParse, self).__call__(node)
425 def visit_CClassDefNode(self, node):
426 old = self.scope_type
427 self.scope_type = 'cclass'
428 self.visitchildren(node)
429 self.scope_type = old
432 def visit_FuncDefNode(self, node):
433 # FuncDefNode always come with an implementation (without
434 # an imp they are CVarDefNodes..)
435 err = self.ERR_INLINE_ONLY
437 if (isinstance(node, DefNode) and self.scope_type == 'cclass'
438 and node.name in ('__getbuffer__', '__releasebuffer__')):
439 err = None # allow these slots
441 if isinstance(node, CFuncDefNode):
442 if u'inline' in node.modifiers and self.scope_type == 'pxd':
443 node.inline_in_pxd = True
444 if node.visibility != 'private':
445 err = self.ERR_NOGO_WITH_INLINE % node.visibility
447 err = self.ERR_NOGO_WITH_INLINE % 'api'
449 err = None # allow inline function
451 err = self.ERR_INLINE_ONLY
454 self.context.nonfatal_error(PostParseError(node.pos, err))
459 class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
461 After parsing, directives can be stored in a number of places:
462 - #cython-comments at the top of the file (stored in ModuleNode)
463 - Command-line arguments overriding these
464 - @cython.directivename decorators
465 - with cython.directivename: statements
467 This transform is responsible for interpreting these various sources
468 and store the directive in two ways:
469 - Set the directives attribute of the ModuleNode for global directives.
470 - Use a CompilerDirectivesNode to override directives for a subtree.
472 (The first one is primarily to not have to modify with the tree
473 structure, so that ModuleNode stay on top.)
475 The directives are stored in dictionaries from name to value in effect.
476 Each such dictionary is always filled in for all possible directives,
477 using default values where no value is given by the user.
479 The available directives are controlled in Options.py.
481 Note that we have to run this prior to analysis, and so some minor
482 duplication of functionality has to occur: We manually track cimports
483 and which names the "cython" module may have been imported to.
485 unop_method_nodes = {
486 'typeof': TypeofNode,
488 'operator.address': AmpersandNode,
489 'operator.dereference': DereferenceNode,
490 'operator.preincrement' : inc_dec_constructor(True, '++'),
491 'operator.predecrement' : inc_dec_constructor(True, '--'),
492 'operator.postincrement': inc_dec_constructor(False, '++'),
493 'operator.postdecrement': inc_dec_constructor(False, '--'),
495 # For backwards compatability.
496 'address': AmpersandNode,
499 special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof',
500 'cast', 'pointer', 'compiled', 'NULL']
501 + unop_method_nodes.keys())
503 def __init__(self, context, compilation_directive_defaults):
504 super(InterpretCompilerDirectives, self).__init__(context)
505 self.compilation_directive_defaults = {}
506 for key, value in compilation_directive_defaults.iteritems():
507 self.compilation_directive_defaults[unicode(key)] = value
508 self.cython_module_names = set()
509 self.directive_names = {}
511 def check_directive_scope(self, pos, directive, scope):
512 legal_scopes = Options.directive_scopes.get(directive, None)
513 if legal_scopes and scope not in legal_scopes:
514 self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
515 'is not allowed in %s scope' % (directive, scope)))
520 # Set up processing and handle the cython: comments.
521 def visit_ModuleNode(self, node):
522 for key, value in node.directive_comments.iteritems():
523 if not self.check_directive_scope(node.pos, key, 'module'):
524 self.wrong_scope_error(node.pos, key, 'module')
525 del node.directive_comments[key]
527 directives = copy.copy(Options.directive_defaults)
528 directives.update(self.compilation_directive_defaults)
529 directives.update(node.directive_comments)
530 self.directives = directives
531 node.directives = directives
532 self.visitchildren(node)
533 node.cython_module_names = self.cython_module_names
536 # The following four functions track imports and cimports that
537 # begin with "cython"
538 def is_cython_directive(self, name):
539 return (name in Options.directive_types or
540 name in self.special_methods or
541 PyrexTypes.parse_basic_type(name))
543 def visit_CImportStatNode(self, node):
544 if node.module_name == u"cython":
545 self.cython_module_names.add(node.as_name or u"cython")
546 elif node.module_name.startswith(u"cython."):
548 self.directive_names[node.as_name] = node.module_name[7:]
550 self.cython_module_names.add(u"cython")
551 # if this cimport was a compiler directive, we don't
552 # want to leave the cimport node sitting in the tree
556 def visit_FromCImportStatNode(self, node):
557 if (node.module_name == u"cython") or \
558 node.module_name.startswith(u"cython."):
559 submodule = (node.module_name + u".")[7:]
561 for pos, name, as_name, kind in node.imported_names:
562 full_name = submodule + name
563 if self.is_cython_directive(full_name):
566 self.directive_names[as_name] = full_name
568 self.context.nonfatal_error(PostParseError(pos,
569 "Compiler directive imports must be plain imports"))
571 newimp.append((pos, name, as_name, kind))
574 node.imported_names = newimp
577 def visit_FromImportStatNode(self, node):
578 if (node.module.module_name.value == u"cython") or \
579 node.module.module_name.value.startswith(u"cython."):
580 submodule = (node.module.module_name.value + u".")[7:]
582 for name, name_node in node.items:
583 full_name = submodule + name
584 if self.is_cython_directive(full_name):
585 self.directive_names[name_node.name] = full_name
587 newimp.append((name, name_node))
593 def visit_SingleAssignmentNode(self, node):
594 if (isinstance(node.rhs, ImportNode) and
595 node.rhs.module_name.value == u'cython'):
596 node = CImportStatNode(node.pos,
597 module_name = u'cython',
598 as_name = node.lhs.name)
599 self.visit_CImportStatNode(node)
601 self.visitchildren(node)
604 def visit_NameNode(self, node):
605 if node.name in self.cython_module_names:
606 node.is_cython_module = True
608 node.cython_attribute = self.directive_names.get(node.name)
611 def try_to_parse_directives(self, node):
612 # If node is the contents of an directive (in a with statement or
613 # decorator), returns a list of (directivename, value) pairs.
614 # Otherwise, returns None
615 if isinstance(node, CallNode):
616 self.visit(node.function)
617 optname = node.function.as_cython_attribute()
619 directivetype = Options.directive_types.get(optname)
621 args, kwds = node.explicit_args_kwds()
624 if kwds is not None and directivetype is not dict:
625 for keyvalue in kwds.key_value_pairs:
626 key, value = keyvalue
627 sub_optname = "%s.%s" % (optname, key.value)
628 if Options.directive_types.get(sub_optname):
629 directives.append(self.try_to_parse_directive(sub_optname, [value], None, keyvalue.pos))
631 key_value_pairs.append(keyvalue)
632 if not key_value_pairs:
635 kwds.key_value_pairs = key_value_pairs
636 if directives and not kwds and not args:
638 directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
643 def try_to_parse_directive(self, optname, args, kwds, pos):
644 directivetype = Options.directive_types.get(optname)
645 if len(args) == 1 and isinstance(args[0], NoneNode):
646 return optname, Options.directive_defaults[optname]
647 elif directivetype is bool:
648 if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
649 raise PostParseError(pos,
650 'The %s directive takes one compile-time boolean argument' % optname)
651 return (optname, args[0].value)
652 elif directivetype is str:
653 if kwds is not None or len(args) != 1 or not isinstance(args[0], (StringNode, UnicodeNode)):
654 raise PostParseError(pos,
655 'The %s directive takes one compile-time string argument' % optname)
656 return (optname, str(args[0].value))
657 elif directivetype is dict:
659 raise PostParseError(pos,
660 'The %s directive takes no prepositional arguments' % optname)
661 return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
662 elif directivetype is list:
663 if kwds and len(kwds) != 0:
664 raise PostParseError(pos,
665 'The %s directive takes no keyword arguments' % optname)
666 return optname, [ str(arg.value) for arg in args ]
670 def visit_with_directives(self, body, directives):
671 olddirectives = self.directives
672 newdirectives = copy.copy(olddirectives)
673 newdirectives.update(directives)
674 self.directives = newdirectives
675 assert isinstance(body, StatListNode), body
676 retbody = self.visit_Node(body)
677 directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody,
678 directives=newdirectives)
679 self.directives = olddirectives
683 def visit_FuncDefNode(self, node):
686 # Split the decorators into two lists -- real decorators and directives
688 for dec in node.decorators:
689 new_directives = self.try_to_parse_directives(dec.decorator)
690 if new_directives is not None:
691 directives.extend(new_directives)
694 if realdecs and isinstance(node, CFuncDefNode):
695 raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.")
697 node.decorators = realdecs
701 directives.reverse() # Decorators coming first take precedence
702 for directive in directives:
703 name, value = directive
704 legal_scopes = Options.directive_scopes.get(name, None)
705 if not self.check_directive_scope(node.pos, name, 'function'):
708 old_value = optdict[name]
709 # keywords and arg lists can be merged, everything
710 # else overrides completely
711 if isinstance(old_value, dict):
712 old_value.update(value)
713 elif isinstance(old_value, list):
714 old_value.extend(value)
716 optdict[name] = value
718 optdict[name] = value
719 body = StatListNode(node.pos, stats=[node])
720 return self.visit_with_directives(body, optdict)
722 return self.visit_Node(node)
724 def visit_CVarDefNode(self, node):
726 for dec in node.decorators:
727 for directive in self.try_to_parse_directives(dec.decorator) or []:
728 if directive is not None and directive[0] == u'locals':
729 node.directive_locals = directive[1]
731 self.context.nonfatal_error(PostParseError(dec.pos,
732 "Cdef functions can only take cython.locals() decorator."))
735 # Handle with statements
736 def visit_WithStatNode(self, node):
738 for directive in self.try_to_parse_directives(node.manager) or []:
739 if directive is not None:
740 if node.target is not None:
741 self.context.nonfatal_error(
742 PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
744 name, value = directive
745 if self.check_directive_scope(node.pos, name, 'with statement'):
746 directive_dict[name] = value
748 return self.visit_with_directives(node.body, directive_dict)
749 return self.visit_Node(node)
751 class WithTransform(CythonTransform, SkipDeclarations):
753 # EXCINFO is manually set to a variable that contains
754 # the exc_info() tuple that can be generated by the enclosing except
756 template_without_target = TreeFragment(u"""
767 if not EXIT(*EXCINFO):
771 EXIT(None, None, None)
772 """, temps=[u'MGR', u'EXC', u"EXIT"],
773 pipeline=[NormalizeTree(None)])
775 template_with_target = TreeFragment(u"""
778 VALUE = MGR.__enter__()
787 if not EXIT(*EXCINFO):
791 EXIT(None, None, None)
792 MGR = EXIT = VALUE = EXC = None
794 """, temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
795 pipeline=[NormalizeTree(None)])
797 def visit_WithStatNode(self, node):
798 # TODO: Cleanup badly needed
799 TemplateTransform.temp_name_counter += 1
800 handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
802 self.visitchildren(node, ['body'])
803 excinfo_temp = NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
804 if node.target is not None:
805 result = self.template_with_target.substitute({
806 u'EXPR' : node.manager,
808 u'TARGET' : node.target,
809 u'EXCINFO' : excinfo_temp
812 result = self.template_without_target.substitute({
813 u'EXPR' : node.manager,
815 u'EXCINFO' : excinfo_temp
818 # Set except excinfo target to EXCINFO
819 try_except = result.stats[-1].body.stats[-1]
820 try_except.except_clauses[0].excinfo_target = NameNode(node.pos, name=handle)
821 # excinfo_temp.ref(node.pos))
823 # result.stats[-1].body.stats[-1] = TempsBlockNode(
824 # node.pos, temps=[excinfo_temp], body=try_except)
828 def visit_ExprNode(self, node):
829 # With statements are never inside expressions.
833 class DecoratorTransform(CythonTransform, SkipDeclarations):
835 def visit_DefNode(self, func_node):
836 self.visitchildren(func_node)
837 if not func_node.decorators:
839 return self._handle_decorators(
840 func_node, func_node.name)
842 def _visit_CClassDefNode(self, class_node):
843 # This doesn't currently work, so it's disabled (also in the
846 # Problem: assignments to cdef class names do not work. They
847 # would require an additional check anyway, as the extension
848 # type must not change its C type, so decorators cannot
849 # replace an extension type, just alter it and return it.
851 self.visitchildren(class_node)
852 if not class_node.decorators:
854 return self._handle_decorators(
855 class_node, class_node.class_name)
857 def visit_ClassDefNode(self, class_node):
858 self.visitchildren(class_node)
859 if not class_node.decorators:
861 return self._handle_decorators(
862 class_node, class_node.name)
864 def _handle_decorators(self, node, name):
865 decorator_result = NameNode(node.pos, name = name)
866 for decorator in node.decorators[::-1]:
867 decorator_result = SimpleCallNode(
869 function = decorator.decorator,
870 args = [decorator_result])
872 name_node = NameNode(node.pos, name = name)
873 reassignment = SingleAssignmentNode(
876 rhs = decorator_result)
877 return [node, reassignment]
880 class AnalyseDeclarationsTransform(CythonTransform):
882 basic_property = TreeFragment(u"""
886 def __set__(self, value):
888 """, level='c_class')
890 def __call__(self, root):
891 self.env_stack = [root.scope]
892 # needed to determine if a cdef var is declared after it's used.
893 self.seen_vars_stack = []
894 return super(AnalyseDeclarationsTransform, self).__call__(root)
896 def visit_NameNode(self, node):
897 self.seen_vars_stack[-1].add(node.name)
900 def visit_ModuleNode(self, node):
901 self.seen_vars_stack.append(set())
902 node.analyse_declarations(self.env_stack[-1])
903 self.visitchildren(node)
904 self.seen_vars_stack.pop()
907 def visit_LambdaNode(self, node):
908 node.analyse_declarations(self.env_stack[-1])
909 self.visitchildren(node)
912 def visit_ClassDefNode(self, node):
913 self.env_stack.append(node.scope)
914 self.visitchildren(node)
918 def visit_FuncDefNode(self, node):
919 self.seen_vars_stack.append(set())
920 lenv = node.local_scope
921 node.body.analyse_control_flow(lenv) # this will be totally refactored
922 node.declare_arguments(lenv)
923 for var, type_node in node.directive_locals.items():
924 if not lenv.lookup_here(var): # don't redeclare args
925 type = type_node.analyse_as_type(lenv)
927 lenv.declare_var(var, type, type_node.pos)
929 error(type_node.pos, "Not a type")
930 node.body.analyse_declarations(lenv)
931 self.env_stack.append(lenv)
932 self.visitchildren(node)
934 self.seen_vars_stack.pop()
937 def visit_ComprehensionNode(self, node):
938 self.visitchildren(node)
939 node.analyse_declarations(self.env_stack[-1])
942 # Some nodes are no longer needed after declaration
943 # analysis and can be dropped. The analysis was performed
944 # on these nodes in a seperate recursive process from the
945 # enclosing function or module, so we can simply drop them.
946 def visit_CDeclaratorNode(self, node):
947 # necessary to ensure that all CNameDeclaratorNodes are visited.
948 self.visitchildren(node)
951 def visit_CTypeDefNode(self, node):
954 def visit_CBaseTypeNode(self, node):
957 def visit_CEnumDefNode(self, node):
958 if node.visibility == 'public':
963 def visit_CStructOrUnionDefNode(self, node):
966 def visit_CNameDeclaratorNode(self, node):
967 if node.name in self.seen_vars_stack[-1]:
968 entry = self.env_stack[-1].lookup(node.name)
969 if entry is None or entry.visibility != 'extern':
970 warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
971 self.visitchildren(node)
974 def visit_CVarDefNode(self, node):
976 # to ensure all CNameDeclaratorNodes are visited.
977 self.visitchildren(node)
979 if node.need_properties:
980 # cdef public attributes may need type testing on
981 # assignment, so we create a property accesss
982 # mechanism for them.
984 for entry in node.need_properties:
985 property = self.create_Property(entry)
986 property.analyse_declarations(node.dest_scope)
988 stats.append(property)
989 return StatListNode(pos=node.pos, stats=stats)
993 def create_Property(self, entry):
994 template = self.basic_property
995 property = template.substitute({
996 u"ATTR": AttributeNode(pos=entry.pos,
997 obj=NameNode(pos=entry.pos, name="self"),
998 attribute=entry.name),
999 }, pos=entry.pos).stats[0]
1000 property.name = entry.name
1003 class AnalyseExpressionsTransform(CythonTransform):
1005 def visit_ModuleNode(self, node):
1006 node.scope.infer_types()
1007 node.body.analyse_expressions(node.scope)
1008 self.visitchildren(node)
1011 def visit_FuncDefNode(self, node):
1012 node.local_scope.infer_types()
1013 node.body.analyse_expressions(node.local_scope)
1014 self.visitchildren(node)
1017 class AlignFunctionDefinitions(CythonTransform):
1019 This class takes the signatures from a .pxd file and applies them to
1020 the def methods in a .py file.
1023 def visit_ModuleNode(self, node):
1024 self.scope = node.scope
1025 self.directives = node.directives
1026 self.visitchildren(node)
1029 def visit_PyClassDefNode(self, node):
1030 pxd_def = self.scope.lookup(node.name)
1032 if pxd_def.is_cclass:
1033 return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
1035 error(node.pos, "'%s' redeclared" % node.name)
1036 error(pxd_def.pos, "previous declaration here")
1041 def visit_CClassDefNode(self, node, pxd_def=None):
1043 pxd_def = self.scope.lookup(node.class_name)
1045 outer_scope = self.scope
1046 self.scope = pxd_def.type.scope
1047 self.visitchildren(node)
1049 self.scope = outer_scope
1052 def visit_DefNode(self, node):
1053 pxd_def = self.scope.lookup(node.name)
1055 if self.scope.is_c_class_scope and len(pxd_def.type.args) > 0:
1056 # The self parameter type needs adjusting.
1057 pxd_def.type.args[0].type = self.scope.parent_type
1058 if pxd_def.is_cfunction:
1059 node = node.as_cfunction(pxd_def)
1061 error(node.pos, "'%s' redeclared" % node.name)
1062 error(pxd_def.pos, "previous declaration here")
1064 elif self.scope.is_module_scope and self.directives['auto_cpdef']:
1065 node = node.as_cfunction(scope=self.scope)
1066 # Enable this when internal def functions are allowed.
1067 # self.visitchildren(node)
1071 class MarkClosureVisitor(CythonTransform):
1073 needs_closure = False
1075 def visit_FuncDefNode(self, node):
1076 self.needs_closure = False
1077 self.visitchildren(node)
1078 node.needs_closure = self.needs_closure
1079 self.needs_closure = True
1082 def visit_LambdaNode(self, node):
1083 self.needs_closure = False
1084 self.visitchildren(node)
1085 node.needs_closure = self.needs_closure
1086 self.needs_closure = True
1089 def visit_ClassDefNode(self, node):
1090 self.visitchildren(node)
1091 self.needs_closure = True
1094 def visit_YieldNode(self, node):
1095 self.needs_closure = True
1097 class CreateClosureClasses(CythonTransform):
1098 # Output closure classes in module scope for all functions
1101 def visit_ModuleNode(self, node):
1102 self.module_scope = node.scope
1103 self.visitchildren(node)
1106 def create_class_from_scope(self, node, target_module_scope):
1107 as_name = "%s%s" % (Naming.closure_class_prefix, node.entry.cname)
1108 func_scope = node.local_scope
1110 entry = target_module_scope.declare_c_class(name = as_name,
1111 pos = node.pos, defining = True, implementing = True)
1112 func_scope.scope_class = entry
1113 class_scope = entry.type.scope
1114 class_scope.is_internal = True
1115 if node.entry.scope.is_closure_scope:
1116 class_scope.declare_var(pos=node.pos,
1117 name=Naming.outer_scope_cname, # this could conflict?
1118 cname=Naming.outer_scope_cname,
1119 type=node.entry.scope.scope_class.type,
1121 for entry in func_scope.entries.values():
1122 # This is wasteful--we should do this later when we know
1123 # which vars are actually being used inside...
1125 class_scope.declare_var(pos=entry.pos,
1131 def visit_FuncDefNode(self, node):
1132 if node.needs_closure:
1133 self.create_class_from_scope(node, self.module_scope)
1134 self.visitchildren(node)
1138 class GilCheck(VisitorTransform):
1140 Call `node.gil_check(env)` on each node to make sure we hold the
1141 GIL when we need it. Raise an error when on Python operations
1142 inside a `nogil` environment.
1144 def __call__(self, root):
1145 self.env_stack = [root.scope]
1147 return super(GilCheck, self).__call__(root)
1149 def visit_FuncDefNode(self, node):
1150 self.env_stack.append(node.local_scope)
1151 was_nogil = self.nogil
1152 self.nogil = node.local_scope.nogil
1153 if self.nogil and node.nogil_check:
1154 node.nogil_check(node.local_scope)
1155 self.visitchildren(node)
1156 self.env_stack.pop()
1157 self.nogil = was_nogil
1160 def visit_GILStatNode(self, node):
1161 env = self.env_stack[-1]
1162 if self.nogil and node.nogil_check: node.nogil_check()
1163 was_nogil = self.nogil
1164 self.nogil = (node.state == 'nogil')
1165 self.visitchildren(node)
1166 self.nogil = was_nogil
1169 def visit_Node(self, node):
1170 if self.env_stack and self.nogil and node.nogil_check:
1171 node.nogil_check(self.env_stack[-1])
1172 self.visitchildren(node)
1176 class TransformBuiltinMethods(EnvTransform):
1178 def visit_SingleAssignmentNode(self, node):
1179 if node.declaration_only:
1182 self.visitchildren(node)
1185 def visit_AttributeNode(self, node):
1186 self.visitchildren(node)
1187 return self.visit_cython_attribute(node)
1189 def visit_NameNode(self, node):
1190 return self.visit_cython_attribute(node)
1192 def visit_cython_attribute(self, node):
1193 attribute = node.as_cython_attribute()
1195 if attribute == u'compiled':
1196 node = BoolNode(node.pos, value=True)
1197 elif attribute == u'NULL':
1198 node = NullNode(node.pos)
1199 elif not PyrexTypes.parse_basic_type(attribute):
1200 error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
1203 def visit_SimpleCallNode(self, node):
1206 if isinstance(node.function, ExprNodes.NameNode):
1207 if node.function.name == 'locals':
1208 lenv = self.env_stack[-1]
1209 entry = lenv.lookup_here('locals')
1211 # not the builtin 'locals'
1213 if len(node.args) > 0:
1214 error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d" % len(node.args))
1217 items = [ExprNodes.DictItemNode(pos,
1218 key=ExprNodes.StringNode(pos, value=var),
1219 value=ExprNodes.NameNode(pos, name=var)) for var in lenv.entries]
1220 return ExprNodes.DictNode(pos, key_value_pairs=items)
1223 function = node.function.as_cython_attribute()
1225 if function in InterpretCompilerDirectives.unop_method_nodes:
1226 if len(node.args) != 1:
1227 error(node.function.pos, u"%s() takes exactly one argument" % function)
1229 node = InterpretCompilerDirectives.unop_method_nodes[function](node.function.pos, operand=node.args[0])
1230 elif function == u'cast':
1231 if len(node.args) != 2:
1232 error(node.function.pos, u"cast() takes exactly two arguments")
1234 type = node.args[0].analyse_as_type(self.env_stack[-1])
1236 node = TypecastNode(node.function.pos, type=type, operand=node.args[1])
1238 error(node.args[0].pos, "Not a type")
1239 elif function == u'sizeof':
1240 if len(node.args) != 1:
1241 error(node.function.pos, u"sizeof() takes exactly one argument")
1243 type = node.args[0].analyse_as_type(self.env_stack[-1])
1245 node = SizeofTypeNode(node.function.pos, arg_type=type)
1247 node = SizeofVarNode(node.function.pos, operand=node.args[0])
1248 elif function == 'cmod':
1249 if len(node.args) != 2:
1250 error(node.function.pos, u"cmod() takes exactly two arguments")
1252 node = binop_node(node.function.pos, '%', node.args[0], node.args[1])
1253 node.cdivision = True
1254 elif function == 'cdiv':
1255 if len(node.args) != 2:
1256 error(node.function.pos, u"cdiv() takes exactly two arguments")
1258 node = binop_node(node.function.pos, '/', node.args[0], node.args[1])
1259 node.cdivision = True
1261 error(node.function.pos, u"'%s' not a valid cython language construct" % function)
1263 self.visitchildren(node)