symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/lib2to3/fixer_util.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Utility functions, node construction macros, etc."""
       
     2 # Author: Collin Winter
       
     3 
       
     4 # Local imports
       
     5 from .pgen2 import token
       
     6 from .pytree import Leaf, Node
       
     7 from .pygram import python_symbols as syms
       
     8 from . import patcomp
       
     9 
       
    10 
       
    11 ###########################################################
       
    12 ### Common node-construction "macros"
       
    13 ###########################################################
       
    14 
       
    15 def KeywordArg(keyword, value):
       
    16     return Node(syms.argument,
       
    17                 [keyword, Leaf(token.EQUAL, '='), value])
       
    18 
       
    19 def LParen():
       
    20     return Leaf(token.LPAR, "(")
       
    21 
       
    22 def RParen():
       
    23     return Leaf(token.RPAR, ")")
       
    24 
       
    25 def Assign(target, source):
       
    26     """Build an assignment statement"""
       
    27     if not isinstance(target, list):
       
    28         target = [target]
       
    29     if not isinstance(source, list):
       
    30         source.set_prefix(" ")
       
    31         source = [source]
       
    32 
       
    33     return Node(syms.atom,
       
    34                 target + [Leaf(token.EQUAL, "=", prefix=" ")] + source)
       
    35 
       
    36 def Name(name, prefix=None):
       
    37     """Return a NAME leaf"""
       
    38     return Leaf(token.NAME, name, prefix=prefix)
       
    39 
       
    40 def Attr(obj, attr):
       
    41     """A node tuple for obj.attr"""
       
    42     return [obj, Node(syms.trailer, [Dot(), attr])]
       
    43 
       
    44 def Comma():
       
    45     """A comma leaf"""
       
    46     return Leaf(token.COMMA, ",")
       
    47 
       
    48 def Dot():
       
    49     """A period (.) leaf"""
       
    50     return Leaf(token.DOT, ".")
       
    51 
       
    52 def ArgList(args, lparen=LParen(), rparen=RParen()):
       
    53     """A parenthesised argument list, used by Call()"""
       
    54     node = Node(syms.trailer, [lparen.clone(), rparen.clone()])
       
    55     if args:
       
    56         node.insert_child(1, Node(syms.arglist, args))
       
    57     return node
       
    58 
       
    59 def Call(func_name, args=None, prefix=None):
       
    60     """A function call"""
       
    61     node = Node(syms.power, [func_name, ArgList(args)])
       
    62     if prefix is not None:
       
    63         node.set_prefix(prefix)
       
    64     return node
       
    65 
       
    66 def Newline():
       
    67     """A newline literal"""
       
    68     return Leaf(token.NEWLINE, "\n")
       
    69 
       
    70 def BlankLine():
       
    71     """A blank line"""
       
    72     return Leaf(token.NEWLINE, "")
       
    73 
       
    74 def Number(n, prefix=None):
       
    75     return Leaf(token.NUMBER, n, prefix=prefix)
       
    76 
       
    77 def Subscript(index_node):
       
    78     """A numeric or string subscript"""
       
    79     return Node(syms.trailer, [Leaf(token.LBRACE, '['),
       
    80                                index_node,
       
    81                                Leaf(token.RBRACE, ']')])
       
    82 
       
    83 def String(string, prefix=None):
       
    84     """A string leaf"""
       
    85     return Leaf(token.STRING, string, prefix=prefix)
       
    86 
       
    87 def ListComp(xp, fp, it, test=None):
       
    88     """A list comprehension of the form [xp for fp in it if test].
       
    89 
       
    90     If test is None, the "if test" part is omitted.
       
    91     """
       
    92     xp.set_prefix("")
       
    93     fp.set_prefix(" ")
       
    94     it.set_prefix(" ")
       
    95     for_leaf = Leaf(token.NAME, "for")
       
    96     for_leaf.set_prefix(" ")
       
    97     in_leaf = Leaf(token.NAME, "in")
       
    98     in_leaf.set_prefix(" ")
       
    99     inner_args = [for_leaf, fp, in_leaf, it]
       
   100     if test:
       
   101         test.set_prefix(" ")
       
   102         if_leaf = Leaf(token.NAME, "if")
       
   103         if_leaf.set_prefix(" ")
       
   104         inner_args.append(Node(syms.comp_if, [if_leaf, test]))
       
   105     inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)])
       
   106     return Node(syms.atom,
       
   107                        [Leaf(token.LBRACE, "["),
       
   108                         inner,
       
   109                         Leaf(token.RBRACE, "]")])
       
   110 
       
   111 def FromImport(package_name, name_leafs):
       
   112     """ Return an import statement in the form:
       
   113         from package import name_leafs"""
       
   114     # XXX: May not handle dotted imports properly (eg, package_name='foo.bar')
       
   115     #assert package_name == '.' or '.' not in package_name, "FromImport has "\
       
   116     #       "not been tested with dotted package names -- use at your own "\
       
   117     #       "peril!"
       
   118 
       
   119     for leaf in name_leafs:
       
   120         # Pull the leaves out of their old tree
       
   121         leaf.remove()
       
   122 
       
   123     children = [Leaf(token.NAME, 'from'),
       
   124                 Leaf(token.NAME, package_name, prefix=" "),
       
   125                 Leaf(token.NAME, 'import', prefix=" "),
       
   126                 Node(syms.import_as_names, name_leafs)]
       
   127     imp = Node(syms.import_from, children)
       
   128     return imp
       
   129 
       
   130 
       
   131 ###########################################################
       
   132 ### Determine whether a node represents a given literal
       
   133 ###########################################################
       
   134 
       
   135 def is_tuple(node):
       
   136     """Does the node represent a tuple literal?"""
       
   137     if isinstance(node, Node) and node.children == [LParen(), RParen()]:
       
   138         return True
       
   139     return (isinstance(node, Node)
       
   140             and len(node.children) == 3
       
   141             and isinstance(node.children[0], Leaf)
       
   142             and isinstance(node.children[1], Node)
       
   143             and isinstance(node.children[2], Leaf)
       
   144             and node.children[0].value == "("
       
   145             and node.children[2].value == ")")
       
   146 
       
   147 def is_list(node):
       
   148     """Does the node represent a list literal?"""
       
   149     return (isinstance(node, Node)
       
   150             and len(node.children) > 1
       
   151             and isinstance(node.children[0], Leaf)
       
   152             and isinstance(node.children[-1], Leaf)
       
   153             and node.children[0].value == "["
       
   154             and node.children[-1].value == "]")
       
   155 
       
   156 
       
   157 ###########################################################
       
   158 ### Misc
       
   159 ###########################################################
       
   160 
       
   161 
       
   162 consuming_calls = set(["sorted", "list", "set", "any", "all", "tuple", "sum",
       
   163                        "min", "max"])
       
   164 
       
   165 def attr_chain(obj, attr):
       
   166     """Follow an attribute chain.
       
   167 
       
   168     If you have a chain of objects where a.foo -> b, b.foo-> c, etc,
       
   169     use this to iterate over all objects in the chain. Iteration is
       
   170     terminated by getattr(x, attr) is None.
       
   171 
       
   172     Args:
       
   173         obj: the starting object
       
   174         attr: the name of the chaining attribute
       
   175 
       
   176     Yields:
       
   177         Each successive object in the chain.
       
   178     """
       
   179     next = getattr(obj, attr)
       
   180     while next:
       
   181         yield next
       
   182         next = getattr(next, attr)
       
   183 
       
   184 p0 = """for_stmt< 'for' any 'in' node=any ':' any* >
       
   185         | comp_for< 'for' any 'in' node=any any* >
       
   186      """
       
   187 p1 = """
       
   188 power<
       
   189     ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
       
   190       'any' | 'all' | (any* trailer< '.' 'join' >) )
       
   191     trailer< '(' node=any ')' >
       
   192     any*
       
   193 >
       
   194 """
       
   195 p2 = """
       
   196 power<
       
   197     'sorted'
       
   198     trailer< '(' arglist<node=any any*> ')' >
       
   199     any*
       
   200 >
       
   201 """
       
   202 pats_built = False
       
   203 def in_special_context(node):
       
   204     """ Returns true if node is in an environment where all that is required
       
   205         of it is being itterable (ie, it doesn't matter if it returns a list
       
   206         or an itterator).
       
   207         See test_map_nochange in test_fixers.py for some examples and tests.
       
   208         """
       
   209     global p0, p1, p2, pats_built
       
   210     if not pats_built:
       
   211         p1 = patcomp.compile_pattern(p1)
       
   212         p0 = patcomp.compile_pattern(p0)
       
   213         p2 = patcomp.compile_pattern(p2)
       
   214         pats_built = True
       
   215     patterns = [p0, p1, p2]
       
   216     for pattern, parent in zip(patterns, attr_chain(node, "parent")):
       
   217         results = {}
       
   218         if pattern.match(parent, results) and results["node"] is node:
       
   219             return True
       
   220     return False
       
   221 
       
   222 ###########################################################
       
   223 ### The following functions are to find bindings in a suite
       
   224 ###########################################################
       
   225 
       
   226 def make_suite(node):
       
   227     if node.type == syms.suite:
       
   228         return node
       
   229     node = node.clone()
       
   230     parent, node.parent = node.parent, None
       
   231     suite = Node(syms.suite, [node])
       
   232     suite.parent = parent
       
   233     return suite
       
   234 
       
   235 def does_tree_import(package, name, node):
       
   236     """ Returns true if name is imported from package at the
       
   237         top level of the tree which node belongs to.
       
   238         To cover the case of an import like 'import foo', use
       
   239         Null for the package and 'foo' for the name. """
       
   240     # Scamper up to the top level namespace
       
   241     while node.type != syms.file_input:
       
   242         assert node.parent, "Tree is insane! root found before "\
       
   243                            "file_input node was found."
       
   244         node = node.parent
       
   245 
       
   246     binding = find_binding(name, node, package)
       
   247     return bool(binding)
       
   248 
       
   249 _def_syms = set([syms.classdef, syms.funcdef])
       
   250 def find_binding(name, node, package=None):
       
   251     """ Returns the node which binds variable name, otherwise None.
       
   252         If optional argument package is supplied, only imports will
       
   253         be returned.
       
   254         See test cases for examples."""
       
   255     for child in node.children:
       
   256         ret = None
       
   257         if child.type == syms.for_stmt:
       
   258             if _find(name, child.children[1]):
       
   259                 return child
       
   260             n = find_binding(name, make_suite(child.children[-1]), package)
       
   261             if n: ret = n
       
   262         elif child.type in (syms.if_stmt, syms.while_stmt):
       
   263             n = find_binding(name, make_suite(child.children[-1]), package)
       
   264             if n: ret = n
       
   265         elif child.type == syms.try_stmt:
       
   266             n = find_binding(name, make_suite(child.children[2]), package)
       
   267             if n:
       
   268                 ret = n
       
   269             else:
       
   270                 for i, kid in enumerate(child.children[3:]):
       
   271                     if kid.type == token.COLON and kid.value == ":":
       
   272                         # i+3 is the colon, i+4 is the suite
       
   273                         n = find_binding(name, make_suite(child.children[i+4]), package)
       
   274                         if n: ret = n
       
   275         elif child.type in _def_syms and child.children[1].value == name:
       
   276             ret = child
       
   277         elif _is_import_binding(child, name, package):
       
   278             ret = child
       
   279         elif child.type == syms.simple_stmt:
       
   280             ret = find_binding(name, child, package)
       
   281         elif child.type == syms.expr_stmt:
       
   282             if _find(name, child.children[0]):
       
   283                 ret = child
       
   284 
       
   285         if ret:
       
   286             if not package:
       
   287                 return ret
       
   288             if ret.type in (syms.import_name, syms.import_from):
       
   289                 return ret
       
   290     return None
       
   291 
       
   292 _block_syms = set([syms.funcdef, syms.classdef, syms.trailer])
       
   293 def _find(name, node):
       
   294     nodes = [node]
       
   295     while nodes:
       
   296         node = nodes.pop()
       
   297         if node.type > 256 and node.type not in _block_syms:
       
   298             nodes.extend(node.children)
       
   299         elif node.type == token.NAME and node.value == name:
       
   300             return node
       
   301     return None
       
   302 
       
   303 def _is_import_binding(node, name, package=None):
       
   304     """ Will reuturn node if node will import name, or node
       
   305         will import * from package.  None is returned otherwise.
       
   306         See test cases for examples. """
       
   307 
       
   308     if node.type == syms.import_name and not package:
       
   309         imp = node.children[1]
       
   310         if imp.type == syms.dotted_as_names:
       
   311             for child in imp.children:
       
   312                 if child.type == syms.dotted_as_name:
       
   313                     if child.children[2].value == name:
       
   314                         return node
       
   315                 elif child.type == token.NAME and child.value == name:
       
   316                     return node
       
   317         elif imp.type == syms.dotted_as_name:
       
   318             last = imp.children[-1]
       
   319             if last.type == token.NAME and last.value == name:
       
   320                 return node
       
   321         elif imp.type == token.NAME and imp.value == name:
       
   322             return node
       
   323     elif node.type == syms.import_from:
       
   324         # unicode(...) is used to make life easier here, because
       
   325         # from a.b import parses to ['import', ['a', '.', 'b'], ...]
       
   326         if package and unicode(node.children[1]).strip() != package:
       
   327             return None
       
   328         n = node.children[3]
       
   329         if package and _find('as', n):
       
   330             # See test_from_import_as for explanation
       
   331             return None
       
   332         elif n.type == syms.import_as_names and _find(name, n):
       
   333             return node
       
   334         elif n.type == syms.import_as_name:
       
   335             child = n.children[2]
       
   336             if child.type == token.NAME and child.value == name:
       
   337                 return node
       
   338         elif n.type == token.NAME and n.value == name:
       
   339             return node
       
   340         elif package and n.type == token.STAR:
       
   341             return node
       
   342     return None