Pythran.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. # cython: language_level=3
  2. from __future__ import absolute_import
  3. from .PyrexTypes import CType, CTypedefType, CStructOrUnionType
  4. import cython
  5. # Pythran/Numpy specific operations
  6. def has_np_pythran(env):
  7. while env is not None:
  8. directives = getattr(env, 'directives', None)
  9. if directives and env.directives.get('np_pythran', False):
  10. return True
  11. env = env.outer_scope
  12. @cython.ccall
  13. def is_pythran_supported_dtype(type_):
  14. if isinstance(type_, CTypedefType):
  15. return is_pythran_supported_type(type_.typedef_base_type)
  16. return type_.is_numeric
  17. def pythran_type(Ty, ptype="ndarray"):
  18. if Ty.is_buffer:
  19. ndim,dtype = Ty.ndim, Ty.dtype
  20. if isinstance(dtype, CStructOrUnionType):
  21. ctype = dtype.cname
  22. elif isinstance(dtype, CType):
  23. ctype = dtype.sign_and_name()
  24. elif isinstance(dtype, CTypedefType):
  25. ctype = dtype.typedef_cname
  26. else:
  27. raise ValueError("unsupported type %s!" % dtype)
  28. return "pythonic::types::%s<%s,%d>" % (ptype,ctype, ndim)
  29. if Ty.is_pythran_expr:
  30. return Ty.pythran_type
  31. #if Ty.is_none:
  32. # return "decltype(pythonic::__builtin__::None)"
  33. if Ty.is_numeric:
  34. return Ty.sign_and_name()
  35. raise ValueError("unsupported pythran type %s (%s)" % (Ty, type(Ty)))
  36. @cython.cfunc
  37. def type_remove_ref(ty):
  38. return "typename std::remove_reference<%s>::type" % ty
  39. def pythran_binop_type(op, tA, tB):
  40. return "decltype(std::declval<%s>() %s std::declval<%s>())" % (
  41. pythran_type(tA), op, pythran_type(tB))
  42. def pythran_unaryop_type(op, type_):
  43. return "decltype(%sstd::declval<%s>())" % (
  44. op, pythran_type(type_))
  45. @cython.cfunc
  46. def _index_access(index_code, indices):
  47. indexing = ",".join([index_code(idx) for idx in indices])
  48. return ('[%s]' if len(indices) == 1 else '(%s)') % indexing
  49. def _index_type_code(index_with_type):
  50. idx, index_type = index_with_type
  51. if idx.is_slice:
  52. if idx.step.is_none:
  53. func = "contiguous_slice"
  54. n = 2
  55. else:
  56. func = "slice"
  57. n = 3
  58. return "pythonic::types::%s(%s)" % (
  59. func, ",".join(["0"]*n))
  60. elif index_type.is_int:
  61. return "std::declval<%s>()" % index_type.sign_and_name()
  62. elif index_type.is_pythran_expr:
  63. return "std::declval<%s>()" % index_type.pythran_type
  64. raise ValueError("unsupported indexing type %s!" % index_type)
  65. def _index_code(idx):
  66. if idx.is_slice:
  67. values = idx.start, idx.stop, idx.step
  68. if idx.step.is_none:
  69. func = "contiguous_slice"
  70. values = values[:2]
  71. else:
  72. func = "slice"
  73. return "pythonic::types::%s(%s)" % (
  74. func, ",".join((v.pythran_result() for v in values)))
  75. elif idx.type.is_int:
  76. return to_pythran(idx)
  77. elif idx.type.is_pythran_expr:
  78. return idx.pythran_result()
  79. raise ValueError("unsupported indexing type %s" % idx.type)
  80. def pythran_indexing_type(type_, indices):
  81. return type_remove_ref("decltype(std::declval<%s>()%s)" % (
  82. pythran_type(type_),
  83. _index_access(_index_type_code, indices),
  84. ))
  85. def pythran_indexing_code(indices):
  86. return _index_access(_index_code, indices)
  87. def pythran_func_type(func, args):
  88. args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args))
  89. return "decltype(pythonic::numpy::functor::%s{}(%s))" % (func, args)
  90. @cython.ccall
  91. def to_pythran(op, ptype=None):
  92. op_type = op.type
  93. if op_type.is_int:
  94. # Make sure that integer literals always have exactly the type that the templates expect.
  95. return op_type.cast_code(op.result())
  96. if is_type(op_type, ["is_pythran_expr", "is_numeric", "is_float", "is_complex"]):
  97. return op.result()
  98. if op.is_none:
  99. return "pythonic::__builtin__::None"
  100. if ptype is None:
  101. ptype = pythran_type(op_type)
  102. assert op.type.is_pyobject
  103. return "from_python<%s>(%s)" % (ptype, op.py_result())
  104. @cython.cfunc
  105. def is_type(type_, types):
  106. for attr in types:
  107. if getattr(type_, attr, False):
  108. return True
  109. return False
  110. def is_pythran_supported_node_or_none(node):
  111. return node.is_none or is_pythran_supported_type(node.type)
  112. @cython.ccall
  113. def is_pythran_supported_type(type_):
  114. pythran_supported = (
  115. "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_none", "is_complex")
  116. return is_type(type_, pythran_supported) or is_pythran_expr(type_)
  117. def is_pythran_supported_operation_type(type_):
  118. pythran_supported = (
  119. "is_pythran_expr", "is_int", "is_numeric", "is_float", "is_complex")
  120. return is_type(type_,pythran_supported) or is_pythran_expr(type_)
  121. @cython.ccall
  122. def is_pythran_expr(type_):
  123. return type_.is_pythran_expr
  124. def is_pythran_buffer(type_):
  125. return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and
  126. type_.mode in ("c", "strided") and not type_.cast)
  127. def include_pythran_generic(env):
  128. # Generic files
  129. env.add_include_file("pythonic/core.hpp")
  130. env.add_include_file("pythonic/python/core.hpp")
  131. env.add_include_file("pythonic/types/bool.hpp")
  132. env.add_include_file("pythonic/types/ndarray.hpp")
  133. env.add_include_file("<new>") # for placement new
  134. for i in (8, 16, 32, 64):
  135. env.add_include_file("pythonic/types/uint%d.hpp" % i)
  136. env.add_include_file("pythonic/types/int%d.hpp" % i)
  137. for t in ("float", "float32", "float64", "set", "slice", "tuple", "int",
  138. "long", "complex", "complex64", "complex128"):
  139. env.add_include_file("pythonic/types/%s.hpp" % t)