Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

astpeephole.py 2.4KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. # Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
  2. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  3. # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
  4. """Small AST optimizations."""
  5. import _ast
  6. from astroid import nodes
  7. __all__ = ('ASTPeepholeOptimizer', )
  8. try:
  9. _TYPES = (_ast.Str, _ast.Bytes)
  10. except AttributeError:
  11. _TYPES = (_ast.Str, )
  12. class ASTPeepholeOptimizer(object):
  13. """Class for applying small optimizations to generate new AST."""
  14. def optimize_binop(self, node, parent=None):
  15. """Optimize BinOps with string Const nodes on the lhs.
  16. This fixes an infinite recursion crash, where multiple
  17. strings are joined using the addition operator. With a
  18. sufficient number of such strings, astroid will fail
  19. with a maximum recursion limit exceeded. The
  20. function will return a Const node with all the strings
  21. already joined.
  22. Return ``None`` if no AST node can be obtained
  23. through optimization.
  24. """
  25. ast_nodes = []
  26. current = node
  27. while isinstance(current, _ast.BinOp):
  28. # lhs must be a BinOp with the addition operand.
  29. if not isinstance(current.left, _ast.BinOp):
  30. return None
  31. if (not isinstance(current.left.op, _ast.Add)
  32. or not isinstance(current.op, _ast.Add)):
  33. return None
  34. # rhs must a str / bytes.
  35. if not isinstance(current.right, _TYPES):
  36. return None
  37. ast_nodes.append(current.right.s)
  38. current = current.left
  39. if (isinstance(current, _ast.BinOp)
  40. and isinstance(current.left, _TYPES)
  41. and isinstance(current.right, _TYPES)):
  42. # Stop early if we are at the last BinOp in
  43. # the operation
  44. ast_nodes.append(current.right.s)
  45. ast_nodes.append(current.left.s)
  46. break
  47. if not ast_nodes:
  48. return None
  49. # If we have inconsistent types, bail out.
  50. known = type(ast_nodes[0])
  51. if any(not isinstance(element, known)
  52. for element in ast_nodes[1:]):
  53. return None
  54. value = known().join(reversed(ast_nodes))
  55. newnode = nodes.Const(value, node.lineno, node.col_offset, parent)
  56. return newnode