diff options
Diffstat (limited to 'Cython/Compiler/Visitor.py')
-rw-r--r-- | Cython/Compiler/Visitor.py | 79 |
1 files changed, 55 insertions, 24 deletions
diff --git a/Cython/Compiler/Visitor.py b/Cython/Compiler/Visitor.py index a35d13e1d..92e2eb9c0 100644 --- a/Cython/Compiler/Visitor.py +++ b/Cython/Compiler/Visitor.py @@ -1,5 +1,5 @@ # cython: infer_types=True -# cython: language_level=3 +# cython: language_level=3str # cython: auto_pickle=False # @@ -80,7 +80,7 @@ class TreeVisitor(object): def dump_node(self, node): ignored = list(node.child_attrs or []) + [ - u'child_attrs', u'pos', u'gil_message', u'cpp_message', u'subexprs'] + 'child_attrs', 'pos', 'gil_message', 'cpp_message', 'subexprs'] values = [] pos = getattr(node, 'pos', None) if pos: @@ -116,7 +116,7 @@ class TreeVisitor(object): nodes = [] while hasattr(stacktrace, 'tb_frame'): frame = stacktrace.tb_frame - node = frame.f_locals.get(u'self') + node = frame.f_locals.get('self') if isinstance(node, Nodes.Node): code = frame.f_code method_name = code.co_name @@ -153,12 +153,12 @@ class TreeVisitor(object): def find_handler(self, obj): # to resolve, try entire hierarchy cls = type(obj) - pattern = "visit_%s" mro = inspect.getmro(cls) for mro_cls in mro: - handler_method = getattr(self, pattern % mro_cls.__name__, None) + handler_method = getattr(self, "visit_" + mro_cls.__name__, None) if handler_method is not None: return handler_method + print(type(self), cls) if self.access_path: print(self.access_path) @@ -167,10 +167,12 @@ class TreeVisitor(object): raise RuntimeError("Visitor %r does not accept object: %s" % (self, obj)) def visit(self, obj): + # generic def entry point for calls from Python subclasses return self._visit(obj) @cython.final def _visit(self, obj): + # fast cdef entry point for calls from Cython subclasses try: try: handler_method = self.dispatch_table[type(obj)] @@ -189,17 +191,20 @@ class TreeVisitor(object): @cython.final def _visitchild(self, child, parent, attrname, idx): + # fast cdef entry point for calls from Cython subclasses self.access_path.append((parent, attrname, idx)) result = self._visit(child) self.access_path.pop() return result - def visitchildren(self, parent, attrs=None): - return self._visitchildren(parent, attrs) + def visitchildren(self, parent, attrs=None, exclude=None): + # generic def entry point for calls from Python subclasses + return self._visitchildren(parent, attrs, exclude) @cython.final @cython.locals(idx=cython.Py_ssize_t) - def _visitchildren(self, parent, attrs): + def _visitchildren(self, parent, attrs, exclude): + # fast cdef entry point for calls from Cython subclasses """ Visits the children of the given parent. If parent is None, returns immediately (returning None). @@ -213,6 +218,7 @@ class TreeVisitor(object): result = {} for attr in parent.child_attrs: if attrs is not None and attr not in attrs: continue + if exclude is not None and attr in exclude: continue child = getattr(parent, attr) if child is not None: if type(child) is list: @@ -246,18 +252,12 @@ class VisitorTransform(TreeVisitor): """ def visitchildren(self, parent, attrs=None, exclude=None): # generic def entry point for calls from Python subclasses - if exclude is not None: - attrs = self._select_attrs(parent.child_attrs if attrs is None else attrs, exclude) - return self._process_children(parent, attrs) + return self._process_children(parent, attrs, exclude) @cython.final - def _select_attrs(self, attrs, exclude): - return [name for name in attrs if name not in exclude] - - @cython.final - def _process_children(self, parent, attrs=None): + def _process_children(self, parent, attrs=None, exclude=None): # fast cdef entry point for calls from Cython subclasses - result = self._visitchildren(parent, attrs) + result = self._visitchildren(parent, attrs, exclude) for attr, newnode in result.items(): if type(newnode) is list: newnode = self._flatten_list(newnode) @@ -276,6 +276,16 @@ class VisitorTransform(TreeVisitor): newlist.append(x) return newlist + def visitchild(self, parent, attr, idx=0): + # Helper to visit specific children from Python subclasses + child = getattr(parent, attr) + if child is not None: + node = self._visitchild(child, parent, attr, idx) + if node is not child: + setattr(parent, attr, node) + child = node + return child + def recurse_to_children(self, node): self._process_children(node) return node @@ -296,8 +306,8 @@ class CythonTransform(VisitorTransform): self.context = context def __call__(self, node): - from . import ModuleNode - if isinstance(node, ModuleNode.ModuleNode): + from .ModuleNode import ModuleNode + if isinstance(node, ModuleNode): self.current_directives = node.directives return super(CythonTransform, self).__call__(node) @@ -370,11 +380,15 @@ class EnvTransform(CythonTransform): self.env_stack.pop() def visit_FuncDefNode(self, node): + self.visit_func_outer_attrs(node) self.enter_scope(node, node.local_scope) - self._process_children(node) + self.visitchildren(node, attrs=None, exclude=node.outer_attrs) self.exit_scope() return node + def visit_func_outer_attrs(self, node): + self.visitchildren(node, attrs=node.outer_attrs) + def visit_GeneratorBodyDefNode(self, node): self._process_children(node) return node @@ -569,7 +583,18 @@ class MethodDispatcherTransform(EnvTransform): ### dispatch to specific handlers def _find_handler(self, match_name, has_kwargs): - call_type = has_kwargs and 'general' or 'simple' + try: + match_name.encode('ascii') + except UnicodeEncodeError: + # specifically when running the Cython compiler under Python 2 + # getattr can't take a unicode string. + # Classes with unicode names won't have specific handlers and thus it + # should be OK to return None. + # Doing the test here ensures that the same code gets run on + # Python 2 and 3 + return None + + call_type = 'general' if has_kwargs else 'simple' handler = getattr(self, '_handle_%s_%s' % (call_type, match_name), None) if handler is None: handler = getattr(self, '_handle_any_%s' % match_name, None) @@ -662,8 +687,8 @@ class MethodDispatcherTransform(EnvTransform): method_handler = self._find_handler( "method_%s_%s" % (type_name, attr_name), kwargs) if method_handler is None: - if (attr_name in TypeSlots.method_name_to_slot - or attr_name == '__new__'): + if (attr_name in TypeSlots.special_method_names + or attr_name in ['__new__', '__class__']): method_handler = self._find_handler( "slot%s" % attr_name, kwargs) if method_handler is None: @@ -733,7 +758,7 @@ class NodeFinder(TreeVisitor): elif node is self.node: self.found = True else: - self._visitchildren(node, None) + self._visitchildren(node, None, None) def tree_contains(tree, node): finder = NodeFinder(node) @@ -821,6 +846,12 @@ class PrintTree(TreeVisitor): result += "(type=%s, name=\"%s\")" % (repr(node.type), node.name) elif isinstance(node, Nodes.DefNode): result += "(name=\"%s\")" % node.name + elif isinstance(node, Nodes.CFuncDefNode): + result += "(name=\"%s\")" % node.declared_name() + elif isinstance(node, ExprNodes.AttributeNode): + result += "(type=%s, attribute=\"%s\")" % (repr(node.type), node.attribute) + elif isinstance(node, (ExprNodes.ConstNode, ExprNodes.PyConstNode)): + result += "(type=%s, value=%r)" % (repr(node.type), node.value) elif isinstance(node, ExprNodes.ExprNode): t = node.type result += "(type=%s)" % repr(t) |