/pypy/module/cpyext/number.py

https://github.com/alemacgo/pypy · Python · 120 lines · 85 code · 15 blank · 20 comment · 8 complexity · f4210c90ad113d49750c725a05ece6ba MD5 · raw file

  1. from pypy.interpreter.error import OperationError
  2. from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, Py_ssize_t
  3. from pypy.module.cpyext.pyobject import PyObject
  4. from pypy.rpython.lltypesystem import rffi, lltype
  5. from pypy.tool.sourcetools import func_with_new_name
  6. @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
  7. def PyIndex_Check(space, w_obj):
  8. """Returns True if o is an index integer (has the nb_index slot of the
  9. tp_as_number structure filled in).
  10. """
  11. try:
  12. space.index(w_obj)
  13. return 1
  14. except OperationError:
  15. return 0
  16. @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
  17. def PyNumber_Check(space, w_obj):
  18. """Returns 1 if the object o provides numeric protocols, and false otherwise.
  19. This function always succeeds."""
  20. try:
  21. space.float_w(w_obj)
  22. return 1
  23. except OperationError:
  24. return 0
  25. @cpython_api([PyObject, PyObject], Py_ssize_t, error=-1)
  26. def PyNumber_AsSsize_t(space, w_obj, w_exc):
  27. """Returns o converted to a Py_ssize_t value if o can be interpreted as an
  28. integer. If o can be converted to a Python int or long but the attempt to
  29. convert to a Py_ssize_t value would raise an OverflowError, then the
  30. exc argument is the type of exception that will be raised (usually
  31. IndexError or OverflowError). If exc is NULL, then the
  32. exception is cleared and the value is clipped to PY_SSIZE_T_MIN for a negative
  33. integer or PY_SSIZE_T_MAX for a positive integer.
  34. """
  35. return space.int_w(w_obj) #XXX: this is wrong on win64
  36. @cpython_api([PyObject], PyObject)
  37. def PyNumber_Int(space, w_obj):
  38. """Returns the o converted to an integer object on success, or NULL on failure.
  39. This is the equivalent of the Python expression int(o)."""
  40. return space.int(w_obj)
  41. @cpython_api([PyObject], PyObject)
  42. def PyNumber_Long(space, w_obj):
  43. """Returns the o converted to a long integer object on success, or NULL on
  44. failure. This is the equivalent of the Python expression long(o)."""
  45. return space.long(w_obj)
  46. @cpython_api([PyObject], PyObject)
  47. def PyNumber_Index(space, w_obj):
  48. """Returns the o converted to a Python int or long on success or NULL with a
  49. TypeError exception raised on failure.
  50. """
  51. return space.index(w_obj)
  52. def func_rename(newname):
  53. return lambda func: func_with_new_name(func, newname)
  54. def make_numbermethod(name, spacemeth):
  55. @cpython_api([PyObject, PyObject], PyObject)
  56. @func_rename('PyNumber_%s' % (name,))
  57. def PyNumber_Method(space, w_o1, w_o2):
  58. meth = getattr(space, spacemeth)
  59. return meth(w_o1, w_o2)
  60. def make_unary_numbermethod(name, spacemeth):
  61. @cpython_api([PyObject], PyObject)
  62. @func_rename('PyNumber_%s' % (name,))
  63. def PyNumber_Method(space, w_o1):
  64. meth = getattr(space, spacemeth)
  65. return meth(w_o1)
  66. def make_inplace_numbermethod(name, spacemeth):
  67. spacemeth = 'inplace_' + spacemeth.rstrip('_')
  68. @cpython_api([PyObject, PyObject], PyObject)
  69. @func_rename('PyNumber_InPlace%s' % (name,))
  70. def PyNumber_Method(space, w_o1, w_o2):
  71. meth = getattr(space, spacemeth)
  72. return meth(w_o1, w_o2)
  73. for name, spacemeth in [
  74. ('Add', 'add'),
  75. ('Subtract', 'sub'),
  76. ('Multiply', 'mul'),
  77. ('Divide', 'div'),
  78. ('FloorDivide', 'floordiv'),
  79. ('TrueDivide', 'truediv'),
  80. ('Remainder', 'mod'),
  81. ('Lshift', 'lshift'),
  82. ('Rshift', 'rshift'),
  83. ('And', 'and_'),
  84. ('Xor', 'xor'),
  85. ('Or', 'or_'),
  86. ('Divmod', 'divmod'),
  87. ]:
  88. make_numbermethod(name, spacemeth)
  89. if name != 'Divmod':
  90. make_inplace_numbermethod(name, spacemeth)
  91. for name, spacemeth in [
  92. ('Negative', 'neg'),
  93. ('Positive', 'pos'),
  94. ('Absolute', 'abs'),
  95. ('Invert', 'invert')]:
  96. make_unary_numbermethod(name, spacemeth)
  97. @cpython_api([PyObject, PyObject, PyObject], PyObject)
  98. def PyNumber_Power(space, w_o1, w_o2, w_o3):
  99. return space.pow(w_o1, w_o2, w_o3)
  100. @cpython_api([PyObject, PyObject, PyObject], PyObject)
  101. def PyNumber_InPlacePower(space, w_o1, w_o2, w_o3):
  102. if not space.is_w(w_o3, space.w_None):
  103. raise OperationError(space.w_ValueError, space.wrap(
  104. "PyNumber_InPlacePower with non-None modulus is not supported"))
  105. return space.inplace_pow(w_o1, w_o2)