utils.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. """ Common function use for AST manipulation. """
  2. import gast as ast
  3. from pythran.tables import MODULES
  4. from pythran.conversion import mangle, demangle
  5. from functools import reduce
  6. from contextlib import contextmanager
  7. def isstr(node):
  8. return isinstance(node, ast.Constant) and isinstance(node.value, str)
  9. def isintegral(node):
  10. return isinstance(node, ast.Constant) and isinstance(node.value, (int,
  11. bool))
  12. def isnum(node):
  13. return isinstance(node, ast.Constant) and isinstance(node.value, (int,
  14. float,
  15. bool))
  16. def isextslice(node):
  17. if not isinstance(node, ast.Tuple):
  18. return False
  19. return any(isinstance(elt, ast.Slice) for elt in node.elts)
  20. def ispowi(node):
  21. if not isinstance(node.op, ast.Pow):
  22. return False
  23. attr = 'right' if isinstance(node, ast.BinOp) else 'value'
  24. if not isintegral(getattr(node, attr)):
  25. return False
  26. return getattr(node, attr).value >= 0
  27. def attr_to_path(node):
  28. """ Compute path and final object for an attribute node """
  29. def get_intrinsic_path(modules, attr):
  30. """ Get function path and intrinsic from an ast.Attribute. """
  31. if isinstance(attr, ast.Name):
  32. return modules[demangle(attr.id)], (demangle(attr.id),)
  33. elif isinstance(attr, ast.Attribute):
  34. module, path = get_intrinsic_path(modules, attr.value)
  35. return module[attr.attr], path + (attr.attr,)
  36. obj, path = get_intrinsic_path(MODULES, node)
  37. # hasattr check because `obj` can be a dict (for modules)
  38. if hasattr(obj, 'isliteral') and not obj.isliteral():
  39. path = path[:-1] + ('functor', path[-1])
  40. return obj, ('pythonic', ) + path
  41. def path_to_attr(path):
  42. """
  43. Transform path to ast.Attribute.
  44. >>> import gast as ast
  45. >>> path = ('builtins', 'my', 'constant')
  46. >>> value = path_to_attr(path)
  47. >>> ref = ast.Attribute(
  48. ... value=ast.Attribute(value=ast.Name(id="builtins",
  49. ... ctx=ast.Load(),
  50. ... annotation=None,
  51. ... type_comment=None),
  52. ... attr="my", ctx=ast.Load()),
  53. ... attr="constant", ctx=ast.Load())
  54. >>> ast.dump(ref) == ast.dump(value)
  55. True
  56. """
  57. return reduce(lambda hpath, last: ast.Attribute(hpath, last, ast.Load()),
  58. path[1:], ast.Name(mangle(path[0]), ast.Load(), None, None))
  59. def path_to_node(path):
  60. """
  61. Retrieve a symbol in MODULES based on its path
  62. >>> path = ('math', 'pi')
  63. >>> path_to_node(path) #doctest: +ELLIPSIS
  64. <pythran.intrinsic.ConstantIntr object at 0x...>
  65. """
  66. if len(path) == 1:
  67. return MODULES[path[0]]
  68. else:
  69. return path_to_node(path[:-1])[path[-1]]
  70. def isattr(node):
  71. return (isinstance(node, ast.Call) and
  72. getattr(node.func, 'attr', None) == 'getattr')
  73. def get_variable(assignable):
  74. """
  75. Return modified variable name.
  76. >>> import gast as ast
  77. >>> ref = ast.Subscript(
  78. ... value=ast.Subscript(
  79. ... value=ast.Name('a', ast.Load(), None, None),
  80. ... slice=ast.Name('i', ast.Load(), None, None),
  81. ... ctx=ast.Load()),
  82. ... slice=ast.Name('j', ast.Load(), None, None),
  83. ... ctx=ast.Load())
  84. >>> ast.dump(get_variable(ref))
  85. "Name(id='a', ctx=Load())"
  86. """
  87. msg = "Only name and subscript can be assigned."
  88. assert isinstance(assignable, (ast.Name, ast.Subscript)), msg
  89. while isinstance(assignable, ast.Subscript) or isattr(assignable):
  90. if isattr(assignable):
  91. assignable = assignable.args[0]
  92. else:
  93. assignable = assignable.value
  94. return assignable
  95. def pythran_builtin(name):
  96. return MODULES['builtins']['pythran'][name]
  97. def pythran_builtin_path(name):
  98. assert name in MODULES['builtins']['pythran']
  99. return ('builtins', 'pythran', name)
  100. def pythran_builtin_attr(name):
  101. return path_to_attr(pythran_builtin_path(name))
  102. def cxxid(name):
  103. from pythran.tables import cxx_keywords
  104. return name + '_' * (name in cxx_keywords)
  105. def quote_cxxstring(s):
  106. subs = (('\\', '\\\\'),
  107. ('\n', '\\n'),
  108. ('\r', '\\r'),
  109. ('"', '\\"'),
  110. )
  111. quoted = s
  112. for f, t in subs:
  113. quoted = quoted.replace(f, t)
  114. return quoted
  115. @contextmanager
  116. def pushpop(l, v):
  117. l.append(v)
  118. yield
  119. l.pop()