/extern/python/closured/lib/python2.7/lib2to3/fixes/fix_next.py

https://github.com/atoun/jsrepl
Python | 103 lines | 75 code | 17 blank | 11 comment | 21 complexity | 867ec9c55a12ec1285c38dad26d4bf0b MD5 | raw file
  1. """Fixer for it.next() -> next(it), per PEP 3114."""
  2. # Author: Collin Winter
  3. # Things that currently aren't covered:
  4. # - listcomp "next" names aren't warned
  5. # - "with" statement targets aren't checked
  6. # Local imports
  7. from ..pgen2 import token
  8. from ..pygram import python_symbols as syms
  9. from .. import fixer_base
  10. from ..fixer_util import Name, Call, find_binding
  11. bind_warning = "Calls to builtin next() possibly shadowed by global binding"
  12. class FixNext(fixer_base.BaseFix):
  13. BM_compatible = True
  14. PATTERN = """
  15. power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > >
  16. |
  17. power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > >
  18. |
  19. classdef< 'class' any+ ':'
  20. suite< any*
  21. funcdef< 'def'
  22. name='next'
  23. parameters< '(' NAME ')' > any+ >
  24. any* > >
  25. |
  26. global=global_stmt< 'global' any* 'next' any* >
  27. """
  28. order = "pre" # Pre-order tree traversal
  29. def start_tree(self, tree, filename):
  30. super(FixNext, self).start_tree(tree, filename)
  31. n = find_binding(u'next', tree)
  32. if n:
  33. self.warning(n, bind_warning)
  34. self.shadowed_next = True
  35. else:
  36. self.shadowed_next = False
  37. def transform(self, node, results):
  38. assert results
  39. base = results.get("base")
  40. attr = results.get("attr")
  41. name = results.get("name")
  42. if base:
  43. if self.shadowed_next:
  44. attr.replace(Name(u"__next__", prefix=attr.prefix))
  45. else:
  46. base = [n.clone() for n in base]
  47. base[0].prefix = u""
  48. node.replace(Call(Name(u"next", prefix=node.prefix), base))
  49. elif name:
  50. n = Name(u"__next__", prefix=name.prefix)
  51. name.replace(n)
  52. elif attr:
  53. # We don't do this transformation if we're assigning to "x.next".
  54. # Unfortunately, it doesn't seem possible to do this in PATTERN,
  55. # so it's being done here.
  56. if is_assign_target(node):
  57. head = results["head"]
  58. if "".join([str(n) for n in head]).strip() == u'__builtin__':
  59. self.warning(node, bind_warning)
  60. return
  61. attr.replace(Name(u"__next__"))
  62. elif "global" in results:
  63. self.warning(node, bind_warning)
  64. self.shadowed_next = True
  65. ### The following functions help test if node is part of an assignment
  66. ### target.
  67. def is_assign_target(node):
  68. assign = find_assign(node)
  69. if assign is None:
  70. return False
  71. for child in assign.children:
  72. if child.type == token.EQUAL:
  73. return False
  74. elif is_subtree(child, node):
  75. return True
  76. return False
  77. def find_assign(node):
  78. if node.type == syms.expr_stmt:
  79. return node
  80. if node.type == syms.simple_stmt or node.parent is None:
  81. return None
  82. return find_assign(node.parent)
  83. def is_subtree(root, node):
  84. if root == node:
  85. return True
  86. return any(is_subtree(c, node) for c in root.children)