Index: third_party/logilab/astng/rebuilder.py |
diff --git a/third_party/logilab/astroid/rebuilder.py b/third_party/logilab/astng/rebuilder.py |
similarity index 81% |
rename from third_party/logilab/astroid/rebuilder.py |
rename to third_party/logilab/astng/rebuilder.py |
index 8fa7ee9232bbf2035b3c005730467edcb452a5d1..bac7a0951142723a28291baf25679ccfd28ae335 100644 |
--- a/third_party/logilab/astroid/rebuilder.py |
+++ b/third_party/logilab/astng/rebuilder.py |
@@ -1,27 +1,28 @@ |
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
+# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
+# copyright 2003-2010 Sylvain Thenault, all rights reserved. |
+# contact mailto:thenault@gmail.com |
# |
-# This file is part of astroid. |
+# This file is part of logilab-astng. |
# |
-# astroid is free software: you can redistribute it and/or modify it |
+# logilab-astng is free software: you can redistribute it and/or modify it |
# under the terms of the GNU Lesser General Public License as published by the |
# Free Software Foundation, either version 2.1 of the License, or (at your |
# option) any later version. |
# |
-# astroid is distributed in the hope that it will be useful, but |
+# logilab-astng is distributed in the hope that it will be useful, but |
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License |
# for more details. |
# |
# You should have received a copy of the GNU Lesser General Public License along |
-# with astroid. If not, see <http://www.gnu.org/licenses/>. |
+# with logilab-astng. If not, see <http://www.gnu.org/licenses/>. |
"""this module contains utilities for rebuilding a _ast tree in |
-order to get a single Astroid representation |
+order to get a single ASTNG representation |
""" |
import sys |
-from _ast import ( |
- Expr as Discard, Str, |
+from _ast import (Expr as Discard, Str, |
# binary operators |
Add, Div, FloorDiv, Mod, Mult, Pow, Sub, BitAnd, BitOr, BitXor, |
LShift, RShift, |
@@ -33,7 +34,8 @@ from _ast import ( |
Eq, Gt, GtE, In, Is, IsNot, Lt, LtE, NotEq, NotIn, |
) |
-from astroid import nodes as new |
+from logilab.astng.exceptions import ASTNGBuildingException |
+from logilab.astng import nodes as new |
_BIN_OP_CLASSES = {Add: '+', |
@@ -47,18 +49,15 @@ _BIN_OP_CLASSES = {Add: '+', |
Pow: '**', |
Sub: '-', |
LShift: '<<', |
- RShift: '>>', |
- } |
+ RShift: '>>'} |
_BOOL_OP_CLASSES = {And: 'and', |
- Or: 'or', |
- } |
+ Or: 'or'} |
_UNARY_OP_CLASSES = {UAdd: '+', |
USub: '-', |
Not: 'not', |
- Invert: '~', |
- } |
+ Invert: '~'} |
_CMP_OP_CLASSES = {Eq: '==', |
Gt: '>', |
@@ -69,13 +68,11 @@ _CMP_OP_CLASSES = {Eq: '==', |
Lt: '<', |
LtE: '<=', |
NotEq: '!=', |
- NotIn: 'not in', |
- } |
+ NotIn: 'not in'} |
CONST_NAME_TRANSFORMS = {'None': None, |
'True': True, |
- 'False': False, |
- } |
+ 'False': False} |
REDIRECT = {'arguments': 'Arguments', |
'Attribute': 'Getattr', |
@@ -91,9 +88,7 @@ REDIRECT = {'arguments': 'Arguments', |
'ImportFrom': 'From', |
'keyword': 'Keyword', |
'Repr': 'Backquote', |
- } |
-PY3K = sys.version_info >= (3, 0) |
-PY34 = sys.version_info >= (3, 4) |
+ } |
def _init_set_doc(node, newnode): |
newnode.doc = None |
@@ -121,47 +116,33 @@ def _set_infos(oldnode, newnode, parent): |
newnode.col_offset = oldnode.col_offset |
newnode.set_line_info(newnode.last_child()) # set_line_info accepts None |
-def _create_yield_node(node, parent, rebuilder, factory): |
- newnode = factory() |
- _lineno_parent(node, newnode, parent) |
- if node.value is not None: |
- newnode.value = rebuilder.visit(node.value, newnode) |
- newnode.set_line_info(newnode.last_child()) |
- return newnode |
+ |
class TreeRebuilder(object): |
- """Rebuilds the _ast tree to become an Astroid tree""" |
+ """Rebuilds the _ast tree to become an ASTNG tree""" |
+ |
+ _visit_meths = {} |
+ def __init__(self): |
+ self.init() |
- def __init__(self, manager): |
- self._manager = manager |
+ def init(self): |
self.asscontext = None |
+ self._metaclass = [''] |
self._global_names = [] |
self._from_nodes = [] |
self._delayed_assattr = [] |
- self._visit_meths = {} |
- self._transform = manager.transform |
- |
- 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 self._transform(newnode) |
def visit(self, node, parent): |
cls = node.__class__ |
if cls in self._visit_meths: |
- visit_method = self._visit_meths[cls] |
+ 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 self._transform(visit_method(node, parent)) |
+ return visit_method(node, parent) |
def _save_assignment(self, node, name=None): |
"""save assignement situation since node.parent is not available yet""" |
@@ -179,37 +160,13 @@ class TreeRebuilder(object): |
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.kwonlyargs = [] |
- newnode.kw_defaults = [] |
- vararg, kwarg = node.vararg, node.kwarg |
- # change added in 82732 (7c5c678e4164), vararg and kwarg |
- # are instances of `_ast.arg`, not strings |
- if vararg: |
- if PY34: |
- if vararg.annotation: |
- newnode.varargannotation = self.visit(vararg.annotation, |
- newnode) |
- vararg = vararg.arg |
- elif PY3K and node.varargannotation: |
- newnode.varargannotation = self.visit(node.varargannotation, |
- newnode) |
- if kwarg: |
- if PY34: |
- if kwarg.annotation: |
- newnode.kwargannotation = self.visit(kwarg.annotation, |
- newnode) |
- kwarg = kwarg.arg |
- elif PY3K: |
- if node.kwargannotation: |
- newnode.kwargannotation = self.visit(node.kwargannotation, |
- newnode) |
- newnode.vararg = vararg |
- newnode.kwarg = kwarg |
+ newnode.vararg = node.vararg |
+ newnode.kwarg = node.kwarg |
# save argument names in locals: |
- if vararg: |
- newnode.parent.set_local(vararg, newnode) |
- if kwarg: |
- newnode.parent.set_local(kwarg, newnode) |
+ if node.vararg: |
+ newnode.parent.set_local(newnode.vararg, newnode) |
+ if node.kwarg: |
+ newnode.parent.set_local(newnode.kwarg, newnode) |
newnode.set_line_info(newnode.last_child()) |
return newnode |
@@ -245,8 +202,8 @@ class TreeRebuilder(object): |
# set some function or metaclass infos XXX explain ? |
klass = newnode.parent.frame() |
if (isinstance(klass, new.Class) |
- and isinstance(newnode.value, new.CallFunc) |
- and isinstance(newnode.value.func, new.Name)): |
+ 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: |
@@ -259,6 +216,9 @@ class TreeRebuilder(object): |
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 |
@@ -330,7 +290,8 @@ class TreeRebuilder(object): |
return newnode |
def visit_class(self, node, parent): |
- """visit a Class node to become astroid""" |
+ """visit a Class node to become astng""" |
+ self._metaclass.append(self._metaclass[-1]) |
newnode = new.Class(node.name, None) |
_lineno_parent(node, newnode, parent) |
_init_set_doc(node, newnode) |
@@ -339,6 +300,11 @@ class TreeRebuilder(object): |
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 |
+ # current scope |
+ newnode._newstyle = metaclass == 'type' |
newnode.parent.frame().set_local(newnode.name, newnode) |
return newnode |
@@ -360,7 +326,7 @@ class TreeRebuilder(object): |
_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)] |
+ for (op, expr) in zip(node.ops, node.comparators)] |
newnode.set_line_info(newnode.last_child()) |
return newnode |
@@ -379,13 +345,13 @@ class TreeRebuilder(object): |
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 astroid.nodes.Function node |
+ # 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 |
+ decorators= node.decorator_list |
newnode.nodes = [self.visit(child, newnode) for child in decorators] |
newnode.set_line_info(newnode.last_child()) |
return newnode |
@@ -405,7 +371,7 @@ class TreeRebuilder(object): |
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)] |
+ for key, value in zip(node.keys, node.values)] |
newnode.set_line_info(newnode.last_child()) |
return newnode |
@@ -491,14 +457,14 @@ class TreeRebuilder(object): |
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 or None) |
+ 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 astroid""" |
+ """visit an Function node to become astng""" |
self._global_names.append({}) |
newnode = new.Function(node.name, None) |
_lineno_parent(node, newnode, parent) |
@@ -512,23 +478,21 @@ class TreeRebuilder(object): |
decorators = getattr(node, attr) |
if decorators: |
newnode.decorators = self.visit_decorators(node, newnode) |
- if PY3K and node.returns: |
- newnode.returns = self.visit(node.returns, newnode) |
newnode.set_line_info(newnode.last_child()) |
self._global_names.pop() |
frame = newnode.parent.frame() |
if isinstance(frame, new.Class): |
if newnode.name == '__new__': |
- newnode._type = 'classmethod' |
+ newnode.type = 'classmethod' |
else: |
- newnode._type = 'method' |
+ newnode.type = 'method' |
if newnode.decorators is not None: |
for decorator_expr in newnode.decorators.nodes: |
if isinstance(decorator_expr, new.Name): |
if decorator_expr.name in ('classmethod', 'staticmethod'): |
- newnode._type = decorator_expr.name |
+ newnode.type = decorator_expr.name |
elif decorator_expr.name == 'classproperty': |
- newnode._type = 'classmethod' |
+ newnode.type = 'classmethod' |
frame.set_local(newnode.name, newnode) |
return newnode |
@@ -562,7 +526,7 @@ class TreeRebuilder(object): |
return newnode |
def visit_global(self, node, parent): |
- """visit an Global node to become astroid""" |
+ """visit an Global node to become astng""" |
newnode = new.Global(node.names) |
_set_infos(node, newnode, parent) |
if self._global_names: # global at the module level, no effect |
@@ -645,6 +609,16 @@ class TreeRebuilder(object): |
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 |
@@ -726,7 +700,7 @@ class TreeRebuilder(object): |
return newnode |
def visit_set(self, node, parent): |
- """visit a Set node by returning a fresh instance of it""" |
+ """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] |
@@ -814,23 +788,27 @@ class TreeRebuilder(object): |
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) |
- expr = self.visit(node.context_expr, newnode) |
+ newnode.expr = self.visit(node.context_expr, newnode) |
self.asscontext = "Ass" |
if node.optional_vars is not None: |
- vars = self.visit(node.optional_vars, newnode) |
- else: |
- vars = None |
+ newnode.vars = self.visit(node.optional_vars, newnode) |
self.asscontext = None |
- newnode.items = [(expr, vars)] |
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""" |
- return _create_yield_node(node, parent, self, new.Yield) |
+ 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""" |
@@ -838,26 +816,9 @@ class TreeRebuilder3k(TreeRebuilder): |
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 astroid ? |
+ # XXX or we should instead introduce a Arg node in astng ? |
return self.visit_assname(node, parent, node.arg) |
- def visit_nameconstant(self, node, parent): |
- # in Python 3.4 we have NameConstant for True / False / None |
- newnode = new.Const(node.value) |
- _set_infos(node, newnode, parent) |
- return newnode |
- |
- def visit_arguments(self, node, parent): |
- newnode = super(TreeRebuilder3k, self).visit_arguments(node, parent) |
- self.asscontext = "Ass" |
- newnode.kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs] |
- self.asscontext = None |
- newnode.kw_defaults = [self.visit(child, newnode) if child else None for child in node.kw_defaults] |
- newnode.annotations = [ |
- self.visit(arg.annotation, newnode) if arg.annotation else None |
- for arg in node.args] |
- return newnode |
- |
def visit_excepthandler(self, node, parent): |
"""visit an ExceptHandler node by returning a fresh instance of it""" |
newnode = new.ExceptHandler() |
@@ -896,64 +857,6 @@ class TreeRebuilder3k(TreeRebuilder): |
newnode.set_line_info(newnode.last_child()) |
return newnode |
- def visit_try(self, node, parent): |
- # python 3.3 introduce a new Try node replacing TryFinally/TryExcept nodes |
- if node.finalbody: |
- newnode = new.TryFinally() |
- _lineno_parent(node, newnode, parent) |
- newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] |
- if node.handlers: |
- excnode = new.TryExcept() |
- _lineno_parent(node, excnode, newnode) |
- excnode.body = [self.visit(child, excnode) for child in node.body] |
- excnode.handlers = [self.visit(child, excnode) for child in node.handlers] |
- excnode.orelse = [self.visit(child, excnode) for child in node.orelse] |
- excnode.set_line_info(excnode.last_child()) |
- newnode.body = [excnode] |
- else: |
- newnode.body = [self.visit(child, newnode) for child in node.body] |
- elif node.handlers: |
- 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_with(self, node, parent): |
- if 'items' not in node._fields: |
- # python < 3.3 |
- return super(TreeRebuilder3k, self).visit_with(node, parent) |
- |
- newnode = new.With() |
- _lineno_parent(node, newnode, parent) |
- def visit_child(child): |
- expr = self.visit(child.context_expr, newnode) |
- self.asscontext = 'Ass' |
- if child.optional_vars: |
- var = self.visit(child.optional_vars, newnode) |
- else: |
- var = None |
- self.asscontext = None |
- return expr, var |
- newnode.items = [visit_child(child) |
- for child in node.items] |
- newnode.body = [self.visit(child, newnode) for child in node.body] |
- newnode.set_line_info(newnode.last_child()) |
- return newnode |
- |
- def visit_yieldfrom(self, node, parent): |
- return _create_yield_node(node, parent, self, new.YieldFrom) |
- |
- def visit_class(self, node, parent): |
- newnode = super(TreeRebuilder3k, self).visit_class(node, parent) |
- newnode._newstyle = True |
- for keyword in node.keywords: |
- if keyword.arg == 'metaclass': |
- newnode._metaclass = self.visit(keyword, newnode).value |
- break |
- return newnode |
if sys.version_info >= (3, 0): |
TreeRebuilder = TreeRebuilder3k |