PageRenderTime 32ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/number.py

https://bitbucket.org/pypy/pypy/
Python | 157 lines | 120 code | 8 blank | 29 comment | 6 complexity | ffa39780ed81732dd79aae33c75a3200 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.interpreter.error import OperationError, oefmt
  2. from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, Py_ssize_t
  3. from pypy.module.cpyext.pyobject import PyObject, PyObjectP, from_ref, make_ref, Py_DecRef
  4. from rpython.rtyper.lltypesystem import rffi, lltype
  5. from rpython.tool.sourcetools import func_with_new_name
  6. from pypy.module.cpyext.state import State
  7. @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
  8. def PyIndex_Check(space, w_obj):
  9. """Returns True if o is an index integer (has the nb_index slot of the
  10. tp_as_number structure filled in).
  11. """
  12. try:
  13. space.index(w_obj)
  14. return 1
  15. except OperationError:
  16. return 0
  17. @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
  18. def PyNumber_Check(space, w_obj):
  19. """Returns 1 if the object o provides numeric protocols, and false otherwise.
  20. This function always succeeds."""
  21. # According to CPython, this means: w_obj is not None, and
  22. # the type of w_obj has got a method __int__ or __float__.
  23. if w_obj is None:
  24. return 0
  25. if space.lookup(w_obj, '__int__') or space.lookup(w_obj, '__float__'):
  26. return 1
  27. return 0
  28. @cpython_api([PyObject, PyObject], Py_ssize_t, error=-1)
  29. def PyNumber_AsSsize_t(space, w_obj, w_exc):
  30. """Returns o converted to a Py_ssize_t value if o can be interpreted as an
  31. integer. If o can be converted to a Python int or long but the attempt to
  32. convert to a Py_ssize_t value would raise an OverflowError, then the
  33. exc argument is the type of exception that will be raised (usually
  34. IndexError or OverflowError). If exc is NULL, then the
  35. exception is cleared and the value is clipped to PY_SSIZE_T_MIN for a negative
  36. integer or PY_SSIZE_T_MAX for a positive integer.
  37. """
  38. return space.int_w(w_obj) #XXX: this is wrong on win64
  39. @cpython_api([PyObject], PyObject)
  40. def PyNumber_Int(space, w_obj):
  41. """Returns the o converted to an integer object on success, or NULL on failure.
  42. This is the equivalent of the Python expression int(o)."""
  43. return space.call_function(space.w_int, w_obj)
  44. @cpython_api([PyObject], PyObject)
  45. def PyNumber_Long(space, w_obj):
  46. """Returns the o converted to a long integer object on success, or NULL on
  47. failure. This is the equivalent of the Python expression long(o)."""
  48. return space.call_function(space.w_long, w_obj)
  49. @cpython_api([PyObject], PyObject)
  50. def PyNumber_Index(space, w_obj):
  51. """Returns the o converted to a Python int or long on success or NULL with a
  52. TypeError exception raised on failure.
  53. """
  54. return space.index(w_obj)
  55. @cpython_api([PyObjectP, PyObjectP], rffi.INT_real, error=CANNOT_FAIL)
  56. def PyNumber_CoerceEx(space, pp1, pp2):
  57. """This function is similar to PyNumber_Coerce(), except that it returns
  58. 1 when the conversion is not possible and when no error is raised.
  59. Reference counts are still not increased in this case."""
  60. retVal = PyNumber_Coerce(space, pp1, pp2)
  61. if retVal != 0:
  62. return 1
  63. return 0
  64. @cpython_api([PyObjectP, PyObjectP], rffi.INT_real, error=CANNOT_FAIL)
  65. def PyNumber_Coerce(space, pp1, pp2):
  66. """This function takes the addresses of two variables of type PyObject*. If
  67. the objects pointed to by *p1 and *p2 have the same type, increment their
  68. reference count and return 0 (success). If the objects can be converted to a
  69. common numeric type, replace *p1 and *p2 by their converted value (with
  70. 'new' reference counts), and return 0. If no conversion is possible, or if
  71. some other error occurs, return -1 (failure) and don't increment the
  72. reference counts. The call PyNumber_Coerce(&o1, &o2) is equivalent to the
  73. Python statement o1, o2 = coerce(o1, o2)."""
  74. w_obj1 = from_ref(space, pp1[0])
  75. w_obj2 = from_ref(space, pp2[0])
  76. try:
  77. w_res = space.coerce(w_obj1, w_obj2)
  78. except (TypeError, OperationError):
  79. state = space.fromcache(State)
  80. state.clear_exception()
  81. return -1
  82. w_res1, w_res2 = space.unpackiterable(w_res, 2)
  83. pp1[0] = make_ref(space, w_res1)
  84. pp2[0] = make_ref(space, w_res2)
  85. return 0
  86. def func_rename(newname):
  87. return lambda func: func_with_new_name(func, newname)
  88. def make_numbermethod(name, spacemeth):
  89. @cpython_api([PyObject, PyObject], PyObject)
  90. @func_rename('PyNumber_%s' % (name,))
  91. def PyNumber_Method(space, w_o1, w_o2):
  92. meth = getattr(space, spacemeth)
  93. return meth(w_o1, w_o2)
  94. def make_unary_numbermethod(name, spacemeth):
  95. @cpython_api([PyObject], PyObject)
  96. @func_rename('PyNumber_%s' % (name,))
  97. def PyNumber_Method(space, w_o1):
  98. meth = getattr(space, spacemeth)
  99. return meth(w_o1)
  100. def make_inplace_numbermethod(name, spacemeth):
  101. spacemeth = 'inplace_' + spacemeth.rstrip('_')
  102. @cpython_api([PyObject, PyObject], PyObject)
  103. @func_rename('PyNumber_InPlace%s' % (name,))
  104. def PyNumber_Method(space, w_o1, w_o2):
  105. meth = getattr(space, spacemeth)
  106. return meth(w_o1, w_o2)
  107. for name, spacemeth in [
  108. ('Add', 'add'),
  109. ('Subtract', 'sub'),
  110. ('Multiply', 'mul'),
  111. ('Divide', 'div'),
  112. ('FloorDivide', 'floordiv'),
  113. ('TrueDivide', 'truediv'),
  114. ('Remainder', 'mod'),
  115. ('Lshift', 'lshift'),
  116. ('Rshift', 'rshift'),
  117. ('And', 'and_'),
  118. ('Xor', 'xor'),
  119. ('Or', 'or_'),
  120. ('Divmod', 'divmod'),
  121. ]:
  122. make_numbermethod(name, spacemeth)
  123. if name != 'Divmod':
  124. make_inplace_numbermethod(name, spacemeth)
  125. for name, spacemeth in [
  126. ('Negative', 'neg'),
  127. ('Positive', 'pos'),
  128. ('Absolute', 'abs'),
  129. ('Invert', 'invert')]:
  130. make_unary_numbermethod(name, spacemeth)
  131. @cpython_api([PyObject, PyObject, PyObject], PyObject)
  132. def PyNumber_Power(space, w_o1, w_o2, w_o3):
  133. return space.pow(w_o1, w_o2, w_o3)
  134. @cpython_api([PyObject, PyObject, PyObject], PyObject)
  135. def PyNumber_InPlacePower(space, w_o1, w_o2, w_o3):
  136. if not space.is_w(w_o3, space.w_None):
  137. raise oefmt(space.w_ValueError,
  138. "PyNumber_InPlacePower with non-None modulus is not "
  139. "supported")
  140. return space.inplace_pow(w_o1, w_o2)