diff --git a/_nodes_ast.py b/_nodes_ast.py index 617e128ee2..d852f5f7e8 100644 --- a/_nodes_ast.py +++ b/_nodes_ast.py @@ -112,7 +112,7 @@ def _init_set_doc(node, newnode): - node.doc = None + newnode.doc = None try: if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, _Str): newnode.tolineno = node.body[0].lineno @@ -121,7 +121,6 @@ def _init_set_doc(node, newnode): except IndexError: pass # ast built from scratch - def native_repr_tree(node, indent='', _done=None): if _done is None: _done = set() @@ -356,7 +355,7 @@ def visit_from(self, node): newnode = new.From(node.module, names) return newnode - def visit_function(self, node): + def _visit_function(self, node): """visit a Function node by returning a fresh instance of it""" newnode = new.Function() _init_set_doc(node, newnode) @@ -483,6 +482,7 @@ def visit_pass(self, node): def visit_print(self, node): """visit a Print node by returning a fresh instance of it""" newnode = new.Print() + newnode.nl = node.nl newnode.dest = self.visit(node.dest, node) newnode.values = [self.visit(child, node) for child in node.values] return newnode diff --git a/_nodes_compiler.py b/_nodes_compiler.py index 0ad5d50ad2..d61ad8e5cb 100644 --- a/_nodes_compiler.py +++ b/_nodes_compiler.py @@ -471,7 +471,7 @@ def visit_from(self, node): return newnode - def visit_function(self, node): + def _visit_function(self, node): """visit a Function node by returning a fresh instance of it""" newnode = new.Function() newnode.decorators = self.visit(node.decorators, node) diff --git a/rebuilder.py b/rebuilder.py index 70711e8e6c..2e554f2497 100644 --- a/rebuilder.py +++ b/rebuilder.py @@ -38,12 +38,13 @@ def __init__(self, set_line_info = True): self.asscontext = None self._metaclass = None self._global_names = None - self._delayed = [] + self._delayed = dict((name, []) for name in ('class', 'function', 'assattr')) self.set_line_info = set_line_info + self._asscontext = None def visit(self, node, parent): if node is None: # some attributes of some nodes are just None - print "node with parent %s is None" % parent + print "node with parent %s is None" % parent return None node.parent = parent # XXX it seems that we need it sometimes self.set_asscontext(node, parent) # XXX @@ -58,7 +59,10 @@ def visit(self, node, parent): if newnode is None: return for child in newnode.get_children(): - child.parent = newnode + if child is not None: + child.parent = newnode + else: + print indent + "newnode %s has None as child" % newnode newnode.set_line_info(child) _leave = getattr(self, "leave_%s" % _method_suffix, None ) if _leave: @@ -66,12 +70,6 @@ def visit(self, node, parent): return newnode - def _push(self, node): - """update the stack and init some parts of the Function or Class node - """ - node.locals = {} - node.parent.frame().set_local(node.name, node) - def set_asscontext(self, node, childnode): """set assignment /delete context needed later on by the childnode""" # XXX refactor this method at least, but killing .asscontext would be better @@ -103,20 +101,21 @@ def set_asscontext(self, node, childnode): # take node arguments to be usable as visit/leave methods def push_asscontext(self, node=None): - self.__asscontext = self.asscontext + self._asscontext = self.asscontext self.asscontext = None return True def pop_asscontext(self, node=None): - self.asscontext = self.__asscontext - self.__asscontext = None + self.asscontext = self._asscontext + self._asscontext = None def walk(self, node): - node = self.visit(node, None) + newnode = self.visit(node, None) delayed = self._delayed - while delayed: - dnode = delayed.pop(0) - self.delayed_visit_assattr(dnode) - return node + for name, nodes in self._delayed.items(): + delay_method = getattr(self, 'delayed_' + name) + for node in nodes: + delay_method(node) + return newnode # general visit_ methods ############################################ @@ -127,7 +126,8 @@ def visit_arguments(self, node): # XXX parent... node.parent.set_local(node.kwarg, node) def visit_assign(self, node): - newnode = self._visit_assign(node) + return self._visit_assign(node) + # XXX call leave_assign here ? def xxx_leave_assign(self, newnode): #XXX parent... klass = newnode.parent.frame() @@ -155,7 +155,7 @@ def xxx_leave_assign(self, newnode): #XXX parent... def visit_class(self, node): # TODO """visit an Class node to become astng""" newnode = self._visit_class(node) - self._push(newnode) + newnode.name = node.name self._metaclass.append(self._metaclass[-1]) metaclass = self._metaclass.pop() if not newnode.bases: @@ -164,6 +164,9 @@ def visit_class(self, node): # TODO node._newstyle = metaclass == 'type' return newnode + def delayed_class(self, node): + node.parent.frame().set_local(node.name, node) + def visit_decorators(self, node): # TODO """visiting an Decorators node""" return self._visit_decorators(node) @@ -195,24 +198,30 @@ def visit_from(self, node): # TODO XXX root ! def visit_function(self, node): # XXX parent """visit an Function node to become astng""" self._global_names.append({}) - if isinstance(node.parent.frame(), nodes.Class): - if node.name == '__new__': - node.type = 'classmethod' - else: - node.type = 'method' - self._push(node) - return True + newnode = self._visit_function(node) + self._delayed['function'].append(newnode) + newnode.name = node.name + return newnode def leave_function(self, node): # TODO """leave a Function node -> pop the last item on the stack""" self._global_names.pop() + def delayed_function(self, newnode): + frame = newnode.parent.frame() + if isinstance(frame, nodes.Class): + if newnode.name == '__new__': + newnode.type = 'classmethod' + else: + newnode.type = 'method' + frame.set_local(newnode.name, newnode) + def visit_assattr(self, node): # TODO """visit an Getattr node to become astng""" - self._delayed.append(node) # FIXME + self._delayed['assattr'].append(node) # FIXME self.push_asscontext() return True - visit_delattr = visit_assattr + # XXX visit_delattr = visit_assattr def leave_assattr(self, node): # TODO """visit an Getattr node to become astng""" @@ -224,7 +233,6 @@ def visit_global(self, node): """visit an Global node to become astng""" newnode = nodes.Global(node.names) if self._global_names: # global at the module level, no effect - return nodes.Global(node.names) for name in node.names: self._global_names[-1].setdefault(name, []).append(newnode) return newnode @@ -259,7 +267,7 @@ def visit_assname(self, node): # XXX parent visit_subscript = push_asscontext leave_subscript = pop_asscontext - def delayed_visit_assattr(self, node): + def delayed_assattr(self, node): """visit a AssAttr node -> add name to locals, handle members definition """ diff --git a/scoped_nodes.py b/scoped_nodes.py index f82954c309..30d2123f1f 100644 --- a/scoped_nodes.py +++ b/scoped_nodes.py @@ -613,6 +613,7 @@ class Function(StmtMixIn, Lambda): def __init__(self): self.starargs = None self.kwargs = None + self.locals = {} special_attributes = set(('__name__', '__doc__', '__dict__')) # attributes below are set by the builder module or by raw factories @@ -785,6 +786,7 @@ class Class(StmtMixIn, LocalsDictNodeNG): def __init__(self): self.instance_attrs = {} + self.locals = {} def _newstyle_impl(self, context=None): if context is None: