diff options
author | Julien Jehannet <julien.jehannet@logilab.fr> | 2011-01-18 09:50:25 +0100 |
---|---|---|
committer | Julien Jehannet <julien.jehannet@logilab.fr> | 2011-01-18 09:50:25 +0100 |
commit | db7ea8451a98b437ee635e99d83944f2a9d3acc2 (patch) | |
tree | 0316a63d8dcd1244056c5bedf4f77aba9e5ed986 /rebuilder.py | |
parent | a73ee39ee8abb46d5785f890295aa128766927ed (diff) | |
parent | 3c3c34d9706ff5f9cea065b5544f18a36bb8216c (diff) | |
download | astroid-git-db7ea8451a98b437ee635e99d83944f2a9d3acc2.tar.gz |
(merge py3k changes)
Diffstat (limited to 'rebuilder.py')
-rw-r--r-- | rebuilder.py | 902 |
1 files changed, 730 insertions, 172 deletions
diff --git a/rebuilder.py b/rebuilder.py index de7ca375..d86013e3 100644 --- a/rebuilder.py +++ b/rebuilder.py @@ -29,14 +29,62 @@ # # You should have received a copy of the GNU Lesser General Public License along # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. -"""this module contains utilities for rebuilding a compiler.ast or _ast tree in +"""this module contains utilities for rebuilding a _ast tree in order to get a single ASTNG representation - """ -from logilab.astng import ASTNGBuildingException, InferenceError -from logilab.astng import nodes -from logilab.astng.bases import YES, Instance +import sys +from _ast import (Expr as Discard, Str, + # binary operators + Add, Div, FloorDiv, Mod, Mult, Pow, Sub, BitAnd, BitOr, BitXor, + LShift, RShift, + # logical operators + And, Or, + # unary operators + UAdd, USub, Not, Invert, + # comparison operators + Eq, Gt, GtE, In, Is, IsNot, Lt, LtE, NotEq, NotIn, + ) + +from logilab.astng.exceptions import ASTNGBuildingException +from logilab.astng import nodes as new + + +_BIN_OP_CLASSES = {Add: '+', + BitAnd: '&', + BitOr: '|', + BitXor: '^', + Div: '/', + FloorDiv: '//', + Mod: '%', + Mult: '*', + Pow: '**', + Sub: '-', + LShift: '<<', + RShift: '>>'} + +_BOOL_OP_CLASSES = {And: 'and', + Or: 'or'} + +_UNARY_OP_CLASSES = {UAdd: '+', + USub: '-', + Not: 'not', + Invert: '~'} + +_CMP_OP_CLASSES = {Eq: '==', + Gt: '>', + GtE: '>=', + In: 'in', + Is: 'is', + IsNot: 'is not', + Lt: '<', + LtE: '<=', + NotEq: '!=', + NotIn: 'not in'} + +CONST_NAME_TRANSFORMS = {'None': None, + 'True': True, + 'False': False} REDIRECT = {'arguments': 'Arguments', 'Attribute': 'Getattr', @@ -52,109 +100,212 @@ REDIRECT = {'arguments': 'Arguments', 'ImportFrom': 'From', 'keyword': 'Keyword', 'Repr': 'Backquote', - - 'Add': 'BinOp', - 'Bitand': 'BinOp', - 'Bitor': 'BinOp', - 'Bitxor': 'BinOp', - 'Div': 'BinOp', - 'FloorDiv': 'BinOp', - 'LeftShift': 'BinOp', - 'Mod': 'BinOp', - 'Mul': 'BinOp', - 'Power': 'BinOp', - 'RightShift': 'BinOp', - 'Sub': 'BinOp', - - 'And': 'BoolOp', - 'Or': 'BoolOp', - - 'UnaryAdd': 'UnaryOp', - 'UnarySub': 'UnaryOp', - 'Not': 'UnaryOp', - 'Invert': 'UnaryOp' } -_key_func = lambda node: node.fromlineno -def sort_locals(my_list): - my_list.sort(key=_key_func) +def _init_set_doc(node, newnode): + newnode.doc = None + try: + if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, Str): + newnode.tolineno = node.body[0].lineno + newnode.doc = node.body[0].value.s + node.body = node.body[1:] -class RebuildVisitor(object): - """Visitor to transform an AST to an ASTNG - """ - def __init__(self, manager): - self._manager = manager - self.asscontext = None - self._metaclass = None - self._global_names = None - self._delayed_assattr = [] + except IndexError: + pass # ast built from scratch - def visit(self, node, parent): - if node is None: # some attributes of some nodes are just None - return None - cls_name = node.__class__.__name__ - visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() - visit_method = getattr(self, visit_name) - return visit_method(node, parent) - - def build(self, node, modname, module_file, package): - """rebuild the tree starting with an Module node; - return an astng.Module node - """ +def _lineno_parent(oldnode, newnode, parent): + newnode.parent = parent + if hasattr(oldnode, 'lineno'): + newnode.lineno = oldnode.lineno + +def _set_infos(oldnode, newnode, parent): + newnode.parent = parent + if hasattr(oldnode, 'lineno'): + newnode.lineno = oldnode.lineno + newnode.set_line_info(newnode.last_child()) # set_line_info accepts None + + + + +class TreeRebuilder(object): + """Rebuilds the _ast tree to become an ASTNG tree""" + + _visit_meths = {} + def __init__(self): + self.init() + + def init(self): + self.asscontext = None self._metaclass = [''] self._global_names = [] self._from_nodes = [] - module = self.visit_module(node, modname, package) - module.file = module.path = module_file - # init module cache here else we may get some infinite recursion - # errors while infering delayed assignments - if self._manager is not None: - self._manager._cache[module.name] = module - # handle delayed assattr nodes - for from_node in self._from_nodes: - self._add_from_names_to_locals(from_node, delayed=True) - delay_assattr = self.delayed_assattr - for delayed in self._delayed_assattr: - delay_assattr(delayed) - return module - - def _save_argument_name(self, node): - """save argument names in locals""" + self._delayed_assattr = [] + + def visit(self, node, parent): + cls = node.__class__ + if cls in self._visit_meths: + return self._visit_meths[cls](node, parent) + else: + cls_name = cls.__name__ + visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() + visit_method = getattr(self, visit_name) + self._visit_meths[cls] = visit_method + return visit_method(node, parent) + + def _save_assignment(self, node, name=None): + """save assignement situation since node.parent is not available yet""" + if self._global_names and node.name in self._global_names[-1]: + node.root().set_local(node.name, node) + else: + node.parent.set_local(node.name, node) + + + def visit_arguments(self, node, parent): + """visit a Arguments node by returning a fresh instance of it""" + newnode = new.Arguments() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.args = [self.visit(child, newnode) for child in node.args] + self.asscontext = None + newnode.defaults = [self.visit(child, newnode) for child in node.defaults] + newnode.vararg = node.vararg + newnode.kwarg = node.kwarg + # save argument names in locals: if node.vararg: - node.parent.set_local(node.vararg, node) + newnode.parent.set_local(newnode.vararg, newnode) if node.kwarg: - node.parent.set_local(node.kwarg, node) + newnode.parent.set_local(newnode.kwarg, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + def visit_assattr(self, node, parent): + """visit a AssAttr node by returning a fresh instance of it""" + assc, self.asscontext = self.asscontext, None + newnode = new.AssAttr() + _lineno_parent(node, newnode, parent) + newnode.expr = self.visit(node.expr, newnode) + self.asscontext = assc + self._delayed_assattr.append(newnode) + newnode.set_line_info(newnode.last_child()) + return newnode - # visit_<node> and delayed_<node> methods ################################# + def visit_assert(self, node, parent): + """visit a Assert node by returning a fresh instance of it""" + newnode = new.Assert() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + if node.msg is not None: + newnode.fail = self.visit(node.msg, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode - def _set_assign_infos(self, newnode): - """set some function or metaclass infos""" # XXX right ? + def visit_assign(self, node, parent): + """visit a Assign node by returning a fresh instance of it""" + newnode = new.Assign() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.targets = [self.visit(child, newnode) for child in node.targets] + self.asscontext = None + newnode.value = self.visit(node.value, newnode) + # set some function or metaclass infos XXX explain ? klass = newnode.parent.frame() - if (isinstance(klass, nodes.Class) - and isinstance(newnode.value, nodes.CallFunc) - and isinstance(newnode.value.func, nodes.Name)): + if (isinstance(klass, new.Class) + and isinstance(newnode.value, new.CallFunc) + and isinstance(newnode.value.func, new.Name)): func_name = newnode.value.func.name for ass_node in newnode.targets: try: meth = klass[ass_node.name] - if isinstance(meth, nodes.Function): + if isinstance(meth, new.Function): if func_name in ('classmethod', 'staticmethod'): meth.type = func_name - try: # XXX use setdefault ? - meth.extra_decorators.append(newnode.value) - except AttributeError: - meth.extra_decorators = [newnode.value] + meth.extra_decorators.append(newnode.value) except (AttributeError, KeyError): continue elif getattr(newnode.targets[0], 'name', None) == '__metaclass__': # XXX check more... self._metaclass[-1] = 'type' # XXX get the actual metaclass + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_assname(self, node, parent, node_name=None): + '''visit a node and return a AssName node''' + newnode = new.AssName() + _set_infos(node, newnode, parent) + newnode.name = node_name + self._save_assignment(newnode) + return newnode + + def visit_augassign(self, node, parent): + """visit a AugAssign node by returning a fresh instance of it""" + newnode = new.AugAssign() + _lineno_parent(node, newnode, parent) + newnode.op = _BIN_OP_CLASSES[node.op.__class__] + "=" + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_backquote(self, node, parent): + """visit a Backquote node by returning a fresh instance of it""" + newnode = new.Backquote() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_binop(self, node, parent): + """visit a BinOp node by returning a fresh instance of it""" + newnode = new.BinOp() + _lineno_parent(node, newnode, parent) + newnode.left = self.visit(node.left, newnode) + newnode.right = self.visit(node.right, newnode) + newnode.op = _BIN_OP_CLASSES[node.op.__class__] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_boolop(self, node, parent): + """visit a BoolOp node by returning a fresh instance of it""" + newnode = new.BoolOp() + _lineno_parent(node, newnode, parent) + newnode.values = [self.visit(child, newnode) for child in node.values] + newnode.op = _BOOL_OP_CLASSES[node.op.__class__] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_break(self, node, parent): + """visit a Break node by returning a fresh instance of it""" + newnode = new.Break() + _set_infos(node, newnode, parent) + return newnode + + def visit_callfunc(self, node, parent): + """visit a CallFunc node by returning a fresh instance of it""" + newnode = new.CallFunc() + _lineno_parent(node, newnode, parent) + newnode.func = self.visit(node.func, newnode) + newnode.args = [self.visit(child, newnode) for child in node.args] + if node.starargs is not None: + newnode.starargs = self.visit(node.starargs, newnode) + if node.kwargs is not None: + newnode.kwargs = self.visit(node.kwargs, newnode) + newnode.args.extend(self.visit(child, newnode) for child in node.keywords) + newnode.set_line_info(newnode.last_child()) + return newnode def visit_class(self, node, parent): """visit a Class node to become astng""" self._metaclass.append(self._metaclass[-1]) - newnode = self._visit_class(node, parent) + newnode = new.Class(node.name, None) + _lineno_parent(node, newnode, parent) + _init_set_doc(node, newnode) + newnode.bases = [self.visit(child, newnode) for child in node.bases] + newnode.body = [self.visit(child, newnode) for child in node.body] + if 'decorator_list' in node._fields and node.decorator_list:# py >= 2.6 + newnode.decorators = self.visit_decorators(node, newnode) + newnode.set_line_info(newnode.last_child()) metaclass = self._metaclass.pop() if not newnode.bases: # no base classes, detect new / style old style according to @@ -163,148 +314,555 @@ class RebuildVisitor(object): newnode.parent.frame().set_local(newnode.name, newnode) return newnode - def visit_break(self, node, parent): - """visit a Break node by returning a fresh instance of it""" - newnode = nodes.Break() - self._set_infos(node, newnode, parent) - return newnode - def visit_const(self, node, parent): """visit a Const node by returning a fresh instance of it""" - newnode = nodes.Const(node.value) - self._set_infos(node, newnode, parent) + newnode = new.Const(node.value) + _set_infos(node, newnode, parent) return newnode def visit_continue(self, node, parent): """visit a Continue node by returning a fresh instance of it""" - newnode = nodes.Continue() - self._set_infos(node, newnode, parent) + newnode = new.Continue() + _set_infos(node, newnode, parent) + return newnode + + def visit_compare(self, node, parent): + """visit a Compare node by returning a fresh instance of it""" + newnode = new.Compare() + _lineno_parent(node, newnode, parent) + newnode.left = self.visit(node.left, newnode) + newnode.ops = [(_CMP_OP_CLASSES[op.__class__], self.visit(expr, newnode)) + for (op, expr) in zip(node.ops, node.comparators)] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_comprehension(self, node, parent): + """visit a Comprehension node by returning a fresh instance of it""" + newnode = new.Comprehension() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.iter = self.visit(node.iter, newnode) + newnode.ifs = [self.visit(child, newnode) for child in node.ifs] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_decorators(self, node, parent): + """visit a Decorators node by returning a fresh instance of it""" + # /!\ node is actually a _ast.Function node while + # parent is a astng.nodes.Function node + newnode = new.Decorators() + _lineno_parent(node, newnode, parent) + if 'decorators' in node._fields: # py < 2.6, i.e. 2.5 + decorators = node.decorators + else: + decorators= node.decorator_list + newnode.nodes = [self.visit(child, newnode) for child in decorators] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_delete(self, node, parent): + """visit a Delete node by returning a fresh instance of it""" + newnode = new.Delete() + _lineno_parent(node, newnode, parent) + self.asscontext = "Del" + newnode.targets = [self.visit(child, newnode) for child in node.targets] + self.asscontext = None + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_dict(self, node, parent): + """visit a Dict node by returning a fresh instance of it""" + newnode = new.Dict() + _lineno_parent(node, newnode, parent) + newnode.items = [(self.visit(key, newnode), self.visit(value, newnode)) + for key, value in zip(node.keys, node.values)] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_dictcomp(self, node, parent): + """visit a DictComp node by returning a fresh instance of it""" + newnode = new.DictComp() + _lineno_parent(node, newnode, parent) + newnode.key = self.visit(node.key, newnode) + newnode.value = self.visit(node.value, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_discard(self, node, parent): + """visit a Discard node by returning a fresh instance of it""" + newnode = new.Discard() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) return newnode def visit_ellipsis(self, node, parent): """visit an Ellipsis node by returning a fresh instance of it""" - newnode = nodes.Ellipsis() - self._set_infos(node, newnode, parent) + newnode = new.Ellipsis() + _set_infos(node, newnode, parent) return newnode def visit_emptynode(self, node, parent): """visit an EmptyNode node by returning a fresh instance of it""" - newnode = nodes.EmptyNode() - self._set_infos(node, newnode, parent) + newnode = new.EmptyNode() + _set_infos(node, newnode, parent) return newnode - def _store_from_node(self, node): - """handle From names by adding them to locals now or after""" - # we can not handle wildcard imports if the source module is not - # in the cache since 'import_module' calls the MANAGER and we will - # end up with infinite recursions working with unfinished trees - if node.modname in self._manager._cache: - self._add_from_names_to_locals(node) - else: - self._from_nodes.append(node) - - def _add_from_names_to_locals(self, node, delayed=False): - """store imported names to the locals; - resort the locals if coming from a delayed node - """ - for (name, asname) in node.names: - if name == '*': - try: - imported = node.root().import_module(node.modname) - except ASTNGBuildingException: - continue - for name in imported.wildcard_import_names(): - node.parent.set_local(name, node) - if delayed: - sort_locals(node.parent.scope().locals[name]) + def visit_excepthandler(self, node, parent): + """visit an ExceptHandler node by returning a fresh instance of it""" + newnode = new.ExceptHandler() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.type = self.visit(node.type, newnode) + if node.name is not None: + # /!\ node.name can be a tuple + self.asscontext = "Ass" + newnode.name = self.visit(node.name, newnode) + self.asscontext = None + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.set_line_info(newnode.last_child()) + return newnode - else: - node.parent.set_local(asname or name, node) - if delayed: - sort_locals(node.parent.scope().locals[asname or name]) + def visit_exec(self, node, parent): + """visit an Exec node by returning a fresh instance of it""" + newnode = new.Exec() + _lineno_parent(node, newnode, parent) + newnode.expr = self.visit(node.body, newnode) + if node.globals is not None: + newnode.globals = self.visit(node.globals, newnode) + if node.locals is not None: + newnode.locals = self.visit(node.locals, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_extslice(self, node, parent): + """visit an ExtSlice node by returning a fresh instance of it""" + newnode = new.ExtSlice() + _lineno_parent(node, newnode, parent) + newnode.dims = [self.visit(dim, newnode) for dim in node.dims] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_for(self, node, parent): + """visit a For node by returning a fresh instance of it""" + newnode = new.For() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.iter = self.visit(node.iter, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + newnode.set_line_info(newnode.last_child()) + return newnode + def visit_from(self, node, parent): + """visit a From node by returning a fresh instance of it""" + names = [(alias.name, alias.asname) for alias in node.names] + newnode = new.From(node.module or '', names, node.level) + _set_infos(node, newnode, parent) + # store From names to add them to locals after building + self._from_nodes.append(newnode) + return newnode def visit_function(self, node, parent): """visit an Function node to become astng""" self._global_names.append({}) - newnode = self._visit_function(node, parent) + newnode = new.Function(node.name, None) + _lineno_parent(node, newnode, parent) + _init_set_doc(node, newnode) + newnode.args = self.visit(node.args, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + if 'decorators' in node._fields: # py < 2.6 + attr = 'decorators' + else: + attr = 'decorator_list' + decorators = getattr(node, attr) + if decorators: + newnode.decorators = self.visit_decorators(node, newnode) + newnode.set_line_info(newnode.last_child()) self._global_names.pop() frame = newnode.parent.frame() - if isinstance(frame, nodes.Class): + if isinstance(frame, new.Class): if newnode.name == '__new__': newnode.type = 'classmethod' else: newnode.type = 'method' if newnode.decorators is not None: for decorator_expr in newnode.decorators.nodes: - if isinstance(decorator_expr, nodes.Name) and \ + if isinstance(decorator_expr, new.Name) and \ decorator_expr.name in ('classmethod', 'staticmethod'): newnode.type = decorator_expr.name frame.set_local(newnode.name, newnode) return newnode + def visit_genexpr(self, node, parent): + """visit a GenExpr node by returning a fresh instance of it""" + newnode = new.GenExpr() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_getattr(self, node, parent): + """visit a Getattr node by returning a fresh instance of it""" + if self.asscontext == "Del": + # FIXME : maybe we should reintroduce and visit_delattr ? + # for instance, deactivating asscontext + newnode = new.DelAttr() + elif self.asscontext == "Ass": + # FIXME : maybe we should call visit_assattr ? + newnode = new.AssAttr() + self._delayed_assattr.append(newnode) + else: + newnode = new.Getattr() + _lineno_parent(node, newnode, parent) + asscontext, self.asscontext = self.asscontext, None + newnode.expr = self.visit(node.value, newnode) + self.asscontext = asscontext + newnode.attrname = node.attr + newnode.set_line_info(newnode.last_child()) + return newnode + def visit_global(self, node, parent): """visit an Global node to become astng""" - newnode = nodes.Global(node.names) - self._set_infos(node, newnode, parent) + newnode = new.Global(node.names) + _set_infos(node, newnode, parent) if self._global_names: # global at the module level, no effect for name in node.names: self._global_names[-1].setdefault(name, []).append(newnode) return newnode - def _save_import_locals(self, newnode): - """save import names in parent's locals""" + def visit_if(self, node, parent): + """visit a If node by returning a fresh instance of it""" + newnode = new.If() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_ifexp(self, node, parent): + """visit a IfExp node by returning a fresh instance of it""" + newnode = new.IfExp() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = self.visit(node.body, newnode) + newnode.orelse = self.visit(node.orelse, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_import(self, node, parent): + """visit a Import node by returning a fresh instance of it""" + newnode = new.Import() + _set_infos(node, newnode, parent) + newnode.names = [(alias.name, alias.asname) for alias in node.names] + # save import names in parent's locals: for (name, asname) in newnode.names: name = asname or name newnode.parent.set_local(name.split('.')[0], newnode) + return newnode + + def visit_index(self, node, parent): + """visit a Index node by returning a fresh instance of it""" + newnode = new.Index() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_keyword(self, node, parent): + """visit a Keyword node by returning a fresh instance of it""" + newnode = new.Keyword() + _lineno_parent(node, newnode, parent) + newnode.arg = node.arg + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_lambda(self, node, parent): + """visit a Lambda node by returning a fresh instance of it""" + newnode = new.Lambda() + _lineno_parent(node, newnode, parent) + newnode.args = self.visit(node.args, newnode) + newnode.body = self.visit(node.body, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_list(self, node, parent): + """visit a List node by returning a fresh instance of it""" + newnode = new.List() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_listcomp(self, node, parent): + """visit a ListComp node by returning a fresh instance of it""" + newnode = new.ListComp() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_module(self, node, modname, package): + """visit a Module node by returning a fresh instance of it""" + newnode = new.Module(modname, None) + newnode.package = package + _lineno_parent(node, newnode, parent=None) + _init_set_doc(node, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_name(self, node, parent): + """visit a Name node by returning a fresh instance of it""" + # True and False can be assigned to something in py2x, so we have to + # check first the asscontext + if self.asscontext == "Del": + newnode = new.DelName() + elif self.asscontext is not None: # Ass + assert self.asscontext == "Ass" + newnode = new.AssName() + elif node.id in CONST_NAME_TRANSFORMS: + newnode = new.Const(CONST_NAME_TRANSFORMS[node.id]) + _set_infos(node, newnode, parent) + return newnode + else: + newnode = new.Name() + _lineno_parent(node, newnode, parent) + newnode.name = node.id + # XXX REMOVE me : + if self.asscontext in ('Del', 'Ass'): # 'Aug' ?? + self._save_assignment(newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_bytes(self, node, parent): + """visit a Bytes node by returning a fresh instance of Const""" + newnode = new.Const(node.s) + _set_infos(node, newnode, parent) + return newnode + + def visit_num(self, node, parent): + """visit a Num node by returning a fresh instance of Const""" + newnode = new.Const(node.n) + _set_infos(node, newnode, parent) + return newnode def visit_pass(self, node, parent): """visit a Pass node by returning a fresh instance of it""" - newnode = nodes.Pass() - self._set_infos(node, newnode, parent) + newnode = new.Pass() + _set_infos(node, newnode, parent) return newnode - def _save_assignment(self, node, name=None): - """save assignement situation since node.parent is not available yet""" - if self._global_names and node.name in self._global_names[-1]: - node.root().set_local(node.name, node) - else: - node.parent.set_local(node.name, node) + def visit_str(self, node, parent): + """visit a Str node by returning a fresh instance of Const""" + newnode = new.Const(node.s) + _set_infos(node, newnode, parent) + return newnode - def delayed_assattr(self, node): - """visit a AssAttr node -> add name to locals, handle members - definition - """ - try: - frame = node.frame() - for infered in node.expr.infer(): - if infered is YES: - continue - try: - if infered.__class__ is Instance: - infered = infered._proxied - iattrs = infered.instance_attrs - elif isinstance(infered, Instance): - # Const, Tuple, ... we may be wrong, may be not, but - # anyway we don't want to pollute builtin's namespace - continue - else: - iattrs = infered.locals - except AttributeError: - # XXX log error - #import traceback - #traceback.print_exc() - continue - values = iattrs.setdefault(node.attrname, []) - if node in values: - continue - # get assign in __init__ first XXX useful ? - if frame.name == '__init__' and values and not \ - values[0].frame().name == '__init__': - values.insert(0, node) - else: - values.append(node) - except InferenceError: - pass + def visit_print(self, node, parent): + """visit a Print node by returning a fresh instance of it""" + newnode = new.Print() + _lineno_parent(node, newnode, parent) + newnode.nl = node.nl + if node.dest is not None: + newnode.dest = self.visit(node.dest, newnode) + newnode.values = [self.visit(child, newnode) for child in node.values] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_raise(self, node, parent): + """visit a Raise node by returning a fresh instance of it""" + newnode = new.Raise() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.exc = self.visit(node.type, newnode) + if node.inst is not None: + newnode.inst = self.visit(node.inst, newnode) + if node.tback is not None: + newnode.tback = self.visit(node.tback, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_return(self, node, parent): + """visit a Return node by returning a fresh instance of it""" + newnode = new.Return() + _lineno_parent(node, newnode, parent) + if node.value is not None: + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_set(self, node, parent): + """visit a Tuple node by returning a fresh instance of it""" + newnode = new.Set() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_setcomp(self, node, parent): + """visit a SetComp node by returning a fresh instance of it""" + newnode = new.SetComp() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_slice(self, node, parent): + """visit a Slice node by returning a fresh instance of it""" + newnode = new.Slice() + _lineno_parent(node, newnode, parent) + if node.lower is not None: + newnode.lower = self.visit(node.lower, newnode) + if node.upper is not None: + newnode.upper = self.visit(node.upper, newnode) + if node.step is not None: + newnode.step = self.visit(node.step, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_subscript(self, node, parent): + """visit a Subscript node by returning a fresh instance of it""" + newnode = new.Subscript() + _lineno_parent(node, newnode, parent) + subcontext, self.asscontext = self.asscontext, None + newnode.value = self.visit(node.value, newnode) + newnode.slice = self.visit(node.slice, newnode) + self.asscontext = subcontext + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_tryexcept(self, node, parent): + """visit a TryExcept node by returning a fresh instance of it""" + newnode = new.TryExcept() + _lineno_parent(node, newnode, parent) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.handlers = [self.visit(child, newnode) for child in node.handlers] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_tryfinally(self, node, parent): + """visit a TryFinally node by returning a fresh instance of it""" + newnode = new.TryFinally() + _lineno_parent(node, newnode, parent) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_tuple(self, node, parent): + """visit a Tuple node by returning a fresh instance of it""" + newnode = new.Tuple() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_unaryop(self, node, parent): + """visit a UnaryOp node by returning a fresh instance of it""" + newnode = new.UnaryOp() + _lineno_parent(node, newnode, parent) + newnode.operand = self.visit(node.operand, newnode) + newnode.op = _UNARY_OP_CLASSES[node.op.__class__] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_while(self, node, parent): + """visit a While node by returning a fresh instance of it""" + newnode = new.While() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_with(self, node, parent): + """visit a With node by returning a fresh instance of it""" + newnode = new.With() + _lineno_parent(node, newnode, parent) + newnode.expr = self.visit(node.context_expr, newnode) + self.asscontext = "Ass" + if node.optional_vars is not None: + newnode.vars = self.visit(node.optional_vars, newnode) + self.asscontext = None + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_yield(self, node, parent): + """visit a Yield node by returning a fresh instance of it""" + newnode = new.Yield() + _lineno_parent(node, newnode, parent) + if node.value is not None: + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + +class TreeRebuilder3k(TreeRebuilder): + """extend and overwrite TreeRebuilder for python3k""" + + def visit_arg(self, node, parent): + """visit a arg node by returning a fresh AssName instance""" + # the <arg> node is coming from py>=3.0, but we use AssName in py2.x + # XXX or we should instead introduce a Arg node in astng ? + return self.visit_assname(node, parent, node.arg) + + def visit_excepthandler(self, node, parent): + """visit an ExceptHandler node by returning a fresh instance of it""" + newnode = new.ExceptHandler() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.type = self.visit(node.type, newnode) + if node.name is not None: + newnode.name = self.visit_assname(node, newnode, node.name) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_nonlocal(self, node, parent): + """visit a Nonlocal node and return a new instance of it""" + newnode = new.Nonlocal(node.names) + _set_infos(node, newnode, parent) + return newnode + + def visit_raise(self, node, parent): + """visit a Raise node by returning a fresh instance of it""" + newnode = new.Raise() + _lineno_parent(node, newnode, parent) + # no traceback; anyway it is not used in Pylint + if node.exc is not None: + newnode.exc = self.visit(node.exc, newnode) + if node.cause is not None: + newnode.cause = self.visit(node.cause, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + def visit_starred(self, node, parent): + """visit a Starred node and return a new instance of it""" + newnode = new.Starred() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + newnode.set_line_info(newnode.last_child()) + return newnode + + +if sys.version_info >= (3, 0): + TreeRebuilder = TreeRebuilder3k |