PageRenderTime 74ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/slotdefs.py

https://bitbucket.org/pypy/pypy/
Python | 878 lines | 821 code | 50 blank | 7 comment | 37 complexity | 342b10a32d247fbe23742c614c49a8d4 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from __future__ import with_statement
  2. import re
  3. from rpython.rtyper.lltypesystem import rffi, lltype
  4. from pypy.module.cpyext.api import (
  5. cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES,
  6. mangle_name, pypy_decl)
  7. from pypy.module.cpyext.typeobjectdefs import (
  8. unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc, ternaryfunc,
  9. getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
  10. ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
  11. cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
  12. readbufferproc, ssizessizeobjargproc)
  13. from pypy.module.cpyext.pyobject import from_ref, make_ref, Py_DecRef
  14. from pypy.module.cpyext.pyerrors import PyErr_Occurred
  15. from pypy.module.cpyext.state import State
  16. from pypy.interpreter.error import OperationError, oefmt
  17. from pypy.interpreter.argument import Arguments
  18. from rpython.rlib.buffer import Buffer
  19. from rpython.rlib.unroll import unrolling_iterable
  20. from rpython.rlib.objectmodel import specialize
  21. from rpython.tool.sourcetools import func_renamer
  22. from rpython.rtyper.annlowlevel import llhelper
  23. # XXX: Also defined in object.h
  24. Py_LT = 0
  25. Py_LE = 1
  26. Py_EQ = 2
  27. Py_NE = 3
  28. Py_GT = 4
  29. Py_GE = 5
  30. def check_num_args(space, w_ob, n):
  31. from pypy.module.cpyext.tupleobject import PyTuple_CheckExact
  32. if not PyTuple_CheckExact(space, w_ob):
  33. raise oefmt(space.w_SystemError,
  34. "PyArg_UnpackTuple() argument list is not a tuple")
  35. if n == space.len_w(w_ob):
  36. return
  37. raise oefmt(space.w_TypeError,
  38. "expected %d arguments, got %d",
  39. n, space.len_w(w_ob))
  40. def check_num_argsv(space, w_ob, low, high):
  41. from pypy.module.cpyext.tupleobject import PyTuple_CheckExact
  42. if not PyTuple_CheckExact(space, w_ob):
  43. raise oefmt(space.w_SystemError,
  44. "PyArg_UnpackTuple() argument list is not a tuple")
  45. if low <=space.len_w(w_ob) <= high:
  46. return
  47. raise oefmt(space.w_TypeError,
  48. "expected %d-%d arguments, got %d",
  49. low, high, space.len_w(w_ob))
  50. def wrap_init(space, w_self, w_args, func, w_kwargs):
  51. func_init = rffi.cast(initproc, func)
  52. res = generic_cpy_call(space, func_init, w_self, w_args, w_kwargs)
  53. if rffi.cast(lltype.Signed, res) == -1:
  54. space.fromcache(State).check_and_raise_exception(always=True)
  55. return None
  56. def wrap_unaryfunc(space, w_self, w_args, func):
  57. func_unary = rffi.cast(unaryfunc, func)
  58. check_num_args(space, w_args, 0)
  59. return generic_cpy_call(space, func_unary, w_self)
  60. def wrap_binaryfunc(space, w_self, w_args, func):
  61. func_binary = rffi.cast(binaryfunc, func)
  62. check_num_args(space, w_args, 1)
  63. args_w = space.fixedview(w_args)
  64. return generic_cpy_call(space, func_binary, w_self, args_w[0])
  65. def wrap_binaryfunc_l(space, w_self, w_args, func):
  66. func_binary = rffi.cast(binaryfunc, func)
  67. check_num_args(space, w_args, 1)
  68. args_w = space.fixedview(w_args)
  69. ref = make_ref(space, w_self)
  70. if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
  71. not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
  72. return space.w_NotImplemented
  73. Py_DecRef(space, ref)
  74. return generic_cpy_call(space, func_binary, w_self, args_w[0])
  75. def wrap_binaryfunc_r(space, w_self, w_args, func):
  76. func_binary = rffi.cast(binaryfunc, func)
  77. check_num_args(space, w_args, 1)
  78. args_w = space.fixedview(w_args)
  79. ref = make_ref(space, w_self)
  80. if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
  81. not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
  82. return space.w_NotImplemented
  83. Py_DecRef(space, ref)
  84. return generic_cpy_call(space, func_binary, args_w[0], w_self)
  85. def wrap_ternaryfunc(space, w_self, w_args, func):
  86. # The third argument is optional
  87. func_ternary = rffi.cast(ternaryfunc, func)
  88. check_num_argsv(space, w_args, 1, 2)
  89. args_w = space.fixedview(w_args)
  90. arg3 = space.w_None
  91. if len(args_w) > 1:
  92. arg3 = args_w[1]
  93. return generic_cpy_call(space, func_ternary, w_self, args_w[0], arg3)
  94. def wrap_ternaryfunc_r(space, w_self, w_args, func):
  95. # The third argument is optional
  96. func_ternary = rffi.cast(ternaryfunc, func)
  97. check_num_argsv(space, w_args, 1, 2)
  98. args_w = space.fixedview(w_args)
  99. ref = make_ref(space, w_self)
  100. if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
  101. not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
  102. return space.w_NotImplemented
  103. Py_DecRef(space, ref)
  104. arg3 = space.w_None
  105. if len(args_w) > 1:
  106. arg3 = args_w[1]
  107. return generic_cpy_call(space, func_ternary, args_w[0], w_self, arg3)
  108. def wrap_inquirypred(space, w_self, w_args, func):
  109. func_inquiry = rffi.cast(inquiry, func)
  110. check_num_args(space, w_args, 0)
  111. args_w = space.fixedview(w_args)
  112. res = generic_cpy_call(space, func_inquiry, w_self)
  113. res = rffi.cast(lltype.Signed, res)
  114. if res == -1:
  115. space.fromcache(State).check_and_raise_exception(always=True)
  116. return space.wrap(bool(res))
  117. def wrap_getattr(space, w_self, w_args, func):
  118. func_target = rffi.cast(getattrfunc, func)
  119. check_num_args(space, w_args, 1)
  120. args_w = space.fixedview(w_args)
  121. name_ptr = rffi.str2charp(space.str_w(args_w[0]))
  122. try:
  123. return generic_cpy_call(space, func_target, w_self, name_ptr)
  124. finally:
  125. rffi.free_charp(name_ptr)
  126. def wrap_getattro(space, w_self, w_args, func):
  127. func_target = rffi.cast(getattrofunc, func)
  128. check_num_args(space, w_args, 1)
  129. args_w = space.fixedview(w_args)
  130. return generic_cpy_call(space, func_target, w_self, args_w[0])
  131. def wrap_setattr(space, w_self, w_args, func):
  132. func_target = rffi.cast(setattrofunc, func)
  133. check_num_args(space, w_args, 2)
  134. w_name, w_value = space.fixedview(w_args)
  135. # XXX "Carlo Verre hack"?
  136. res = generic_cpy_call(space, func_target, w_self, w_name, w_value)
  137. if rffi.cast(lltype.Signed, res) == -1:
  138. space.fromcache(State).check_and_raise_exception(always=True)
  139. def wrap_delattr(space, w_self, w_args, func):
  140. func_target = rffi.cast(setattrofunc, func)
  141. check_num_args(space, w_args, 1)
  142. w_name, = space.fixedview(w_args)
  143. # XXX "Carlo Verre hack"?
  144. res = generic_cpy_call(space, func_target, w_self, w_name, None)
  145. if rffi.cast(lltype.Signed, res) == -1:
  146. space.fromcache(State).check_and_raise_exception(always=True)
  147. def wrap_descr_get(space, w_self, w_args, func):
  148. func_target = rffi.cast(descrgetfunc, func)
  149. args_w = space.fixedview(w_args)
  150. if len(args_w) == 1:
  151. w_obj, = args_w
  152. w_type = None
  153. elif len(args_w) == 2:
  154. w_obj, w_type = args_w
  155. else:
  156. raise oefmt(space.w_TypeError,
  157. "expected 1 or 2 arguments, got %d", len(args_w))
  158. if w_obj is space.w_None:
  159. w_obj = None
  160. if w_type is space.w_None:
  161. w_type = None
  162. if w_obj is None and w_type is None:
  163. raise oefmt(space.w_TypeError, "__get__(None, None) is invalid")
  164. return generic_cpy_call(space, func_target, w_self, w_obj, w_type)
  165. def wrap_descr_set(space, w_self, w_args, func):
  166. func_target = rffi.cast(descrsetfunc, func)
  167. check_num_args(space, w_args, 2)
  168. w_obj, w_value = space.fixedview(w_args)
  169. res = generic_cpy_call(space, func_target, w_self, w_obj, w_value)
  170. if rffi.cast(lltype.Signed, res) == -1:
  171. space.fromcache(State).check_and_raise_exception(always=True)
  172. def wrap_descr_delete(space, w_self, w_args, func):
  173. func_target = rffi.cast(descrsetfunc, func)
  174. check_num_args(space, w_args, 1)
  175. w_obj, = space.fixedview(w_args)
  176. res = generic_cpy_call(space, func_target, w_self, w_obj, None)
  177. if rffi.cast(lltype.Signed, res) == -1:
  178. space.fromcache(State).check_and_raise_exception(always=True)
  179. def wrap_call(space, w_self, w_args, func, w_kwds):
  180. func_target = rffi.cast(ternaryfunc, func)
  181. return generic_cpy_call(space, func_target, w_self, w_args, w_kwds)
  182. def wrap_ssizessizeobjargproc(space, w_self, w_args, func):
  183. func_target = rffi.cast(ssizessizeobjargproc, func)
  184. check_num_args(space, w_args, 3)
  185. args_w = space.fixedview(w_args)
  186. i = space.int_w(space.index(args_w[0]))
  187. j = space.int_w(space.index(args_w[1]))
  188. w_y = args_w[2]
  189. return space.wrap(generic_cpy_call(space, func_target, w_self, i, j, w_y))
  190. def wrap_lenfunc(space, w_self, w_args, func):
  191. func_len = rffi.cast(lenfunc, func)
  192. check_num_args(space, w_args, 0)
  193. return space.wrap(generic_cpy_call(space, func_len, w_self))
  194. def wrap_sq_item(space, w_self, w_args, func):
  195. func_target = rffi.cast(ssizeargfunc, func)
  196. check_num_args(space, w_args, 1)
  197. args_w = space.fixedview(w_args)
  198. index = space.int_w(space.index(args_w[0]))
  199. return generic_cpy_call(space, func_target, w_self, index)
  200. def wrap_sq_setitem(space, w_self, w_args, func):
  201. func_target = rffi.cast(ssizeobjargproc, func)
  202. check_num_args(space, w_args, 2)
  203. args_w = space.fixedview(w_args)
  204. index = space.int_w(space.index(args_w[0]))
  205. res = generic_cpy_call(space, func_target, w_self, index, args_w[1])
  206. if rffi.cast(lltype.Signed, res) == -1:
  207. space.fromcache(State).check_and_raise_exception(always=True)
  208. def wrap_sq_delitem(space, w_self, w_args, func):
  209. func_target = rffi.cast(ssizeobjargproc, func)
  210. check_num_args(space, w_args, 1)
  211. args_w = space.fixedview(w_args)
  212. index = space.int_w(space.index(args_w[0]))
  213. null = lltype.nullptr(PyObject.TO)
  214. res = generic_cpy_call(space, func_target, w_self, index, null)
  215. if rffi.cast(lltype.Signed, res) == -1:
  216. space.fromcache(State).check_and_raise_exception(always=True)
  217. # Warning, confusing function name (like CPython). Used only for sq_contains.
  218. def wrap_objobjproc(space, w_self, w_args, func):
  219. func_target = rffi.cast(objobjproc, func)
  220. check_num_args(space, w_args, 1)
  221. w_value, = space.fixedview(w_args)
  222. res = generic_cpy_call(space, func_target, w_self, w_value)
  223. res = rffi.cast(lltype.Signed, res)
  224. if res == -1:
  225. space.fromcache(State).check_and_raise_exception(always=True)
  226. return space.wrap(bool(res))
  227. def wrap_objobjargproc(space, w_self, w_args, func):
  228. func_target = rffi.cast(objobjargproc, func)
  229. check_num_args(space, w_args, 2)
  230. w_key, w_value = space.fixedview(w_args)
  231. res = generic_cpy_call(space, func_target, w_self, w_key, w_value)
  232. if rffi.cast(lltype.Signed, res) == -1:
  233. space.fromcache(State).check_and_raise_exception(always=True)
  234. return space.w_None
  235. def wrap_delitem(space, w_self, w_args, func):
  236. func_target = rffi.cast(objobjargproc, func)
  237. check_num_args(space, w_args, 1)
  238. w_key, = space.fixedview(w_args)
  239. res = generic_cpy_call(space, func_target, w_self, w_key, None)
  240. if rffi.cast(lltype.Signed, res) == -1:
  241. space.fromcache(State).check_and_raise_exception(always=True)
  242. return space.w_None
  243. def wrap_ssizessizeargfunc(space, w_self, w_args, func):
  244. func_target = rffi.cast(ssizessizeargfunc, func)
  245. check_num_args(space, w_args, 2)
  246. args_w = space.fixedview(w_args)
  247. start = space.int_w(args_w[0])
  248. end = space.int_w(args_w[1])
  249. return generic_cpy_call(space, func_target, w_self, start, end)
  250. def wrap_next(space, w_self, w_args, func):
  251. from pypy.module.cpyext.api import generic_cpy_call_expect_null
  252. func_target = rffi.cast(iternextfunc, func)
  253. check_num_args(space, w_args, 0)
  254. w_res = generic_cpy_call_expect_null(space, func_target, w_self)
  255. if not w_res and not PyErr_Occurred(space):
  256. raise OperationError(space.w_StopIteration, space.w_None)
  257. return w_res
  258. def wrap_hashfunc(space, w_self, w_args, func):
  259. func_target = rffi.cast(hashfunc, func)
  260. check_num_args(space, w_args, 0)
  261. return space.wrap(generic_cpy_call(space, func_target, w_self))
  262. class CPyBuffer(Buffer):
  263. # Similar to Py_buffer
  264. _immutable_ = True
  265. def __init__(self, ptr, size, w_obj):
  266. self.ptr = ptr
  267. self.size = size
  268. self.w_obj = w_obj # kept alive
  269. self.readonly = True
  270. def getlength(self):
  271. return self.size
  272. def getitem(self, index):
  273. return self.ptr[index]
  274. def get_raw_address(self):
  275. return rffi.cast(rffi.CCHARP, self.ptr)
  276. def wrap_getreadbuffer(space, w_self, w_args, func):
  277. func_target = rffi.cast(readbufferproc, func)
  278. with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
  279. index = rffi.cast(Py_ssize_t, 0)
  280. size = generic_cpy_call(space, func_target, w_self, index, ptr)
  281. if size < 0:
  282. space.fromcache(State).check_and_raise_exception(always=True)
  283. return space.newbuffer(CPyBuffer(ptr[0], size, w_self))
  284. def get_richcmp_func(OP_CONST):
  285. def inner(space, w_self, w_args, func):
  286. func_target = rffi.cast(richcmpfunc, func)
  287. check_num_args(space, w_args, 1)
  288. w_other, = space.fixedview(w_args)
  289. return generic_cpy_call(space, func_target,
  290. w_self, w_other, rffi.cast(rffi.INT_real, OP_CONST))
  291. return inner
  292. richcmp_eq = get_richcmp_func(Py_EQ)
  293. richcmp_ne = get_richcmp_func(Py_NE)
  294. richcmp_lt = get_richcmp_func(Py_LT)
  295. richcmp_le = get_richcmp_func(Py_LE)
  296. richcmp_gt = get_richcmp_func(Py_GT)
  297. richcmp_ge = get_richcmp_func(Py_GE)
  298. def wrap_cmpfunc(space, w_self, w_args, func):
  299. func_target = rffi.cast(cmpfunc, func)
  300. check_num_args(space, w_args, 1)
  301. w_other, = space.fixedview(w_args)
  302. if not space.issubtype_w(space.type(w_self), space.type(w_other)):
  303. raise oefmt(space.w_TypeError,
  304. "%T.__cmp__(x,y) requires y to be a '%T', not a '%T'",
  305. w_self, w_self, w_other)
  306. return space.wrap(generic_cpy_call(space, func_target, w_self, w_other))
  307. from rpython.rlib.nonconst import NonConstant
  308. SLOTS = {}
  309. @specialize.memo()
  310. def get_slot_tp_function(space, typedef, name):
  311. key = (typedef, name)
  312. try:
  313. return SLOTS[key]
  314. except KeyError:
  315. ret = build_slot_tp_function(space, typedef, name)
  316. SLOTS[key] = ret
  317. return ret
  318. def build_slot_tp_function(space, typedef, name):
  319. w_type = space.gettypeobject(typedef)
  320. header = pypy_decl
  321. if mangle_name('', typedef.name) is None:
  322. header = None
  323. handled = False
  324. # unary functions
  325. for tp_name, attr in [('tp_as_number.c_nb_int', '__int__'),
  326. ('tp_as_number.c_nb_long', '__long__'),
  327. ('tp_as_number.c_nb_float', '__float__'),
  328. ('tp_as_number.c_nb_negative', '__neg__'),
  329. ('tp_as_number.c_nb_positive', '__pos__'),
  330. ('tp_as_number.c_nb_absolute', '__abs__'),
  331. ('tp_as_number.c_nb_invert', '__invert__'),
  332. ('tp_as_number.c_nb_index', '__index__'),
  333. ('tp_as_number.c_nb_hex', '__hex__'),
  334. ('tp_as_number.c_nb_oct', '__oct__'),
  335. ('tp_str', '__str__'),
  336. ('tp_repr', '__repr__'),
  337. ('tp_iter', '__iter__'),
  338. ]:
  339. if name == tp_name:
  340. slot_fn = w_type.getdictvalue(space, attr)
  341. if slot_fn is None:
  342. return
  343. @cpython_api([PyObject], PyObject, header=header)
  344. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  345. def slot_func(space, w_self):
  346. return space.call_function(slot_fn, w_self)
  347. api_func = slot_func.api_func
  348. handled = True
  349. # binary functions
  350. for tp_name, attr in [('tp_as_number.c_nb_add', '__add__'),
  351. ('tp_as_number.c_nb_subtract', '__sub__'),
  352. ('tp_as_number.c_nb_multiply', '__mul__'),
  353. ('tp_as_number.c_nb_divide', '__div__'),
  354. ('tp_as_number.c_nb_remainder', '__mod__'),
  355. ('tp_as_number.c_nb_divmod', '__divmod__'),
  356. ('tp_as_number.c_nb_lshift', '__lshift__'),
  357. ('tp_as_number.c_nb_rshift', '__rshift__'),
  358. ('tp_as_number.c_nb_and', '__and__'),
  359. ('tp_as_number.c_nb_xor', '__xor__'),
  360. ('tp_as_number.c_nb_or', '__or__'),
  361. ('tp_as_sequence.c_sq_concat', '__add__'),
  362. ('tp_as_sequence.c_sq_inplace_concat', '__iadd__')
  363. ]:
  364. if name == tp_name:
  365. slot_fn = w_type.getdictvalue(space, attr)
  366. if slot_fn is None:
  367. return
  368. @cpython_api([PyObject, PyObject], PyObject, header=header)
  369. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  370. def slot_func(space, w_self, w_arg):
  371. return space.call_function(slot_fn, w_self, w_arg)
  372. api_func = slot_func.api_func
  373. handled = True
  374. # binary-with-Py_ssize_t-type
  375. for tp_name, attr in [('tp_as_sequence.c_sq_item', '__getitem'),
  376. ('tp_as_sequence.c_sq_repeat', '__mul__'),
  377. ('tp_as_sequence.c_sq_repeat', '__mul__'),
  378. ('tp_as_sequence.c_sq_inplace_repeat', '__imul__'),
  379. ]:
  380. if name == tp_name:
  381. slot_fn = w_type.getdictvalue(space, attr)
  382. if slot_fn is None:
  383. return
  384. @cpython_api([PyObject, Py_ssize_t], PyObject, header=header)
  385. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  386. def slot_func(space, w_self, arg):
  387. return space.call_function(slot_fn, w_self, space.wrap(arg))
  388. api_func = slot_func.api_func
  389. handled = True
  390. # ternary functions
  391. for tp_name, attr in [('tp_as_number.c_nb_power', '__pow__'),
  392. ]:
  393. if name == tp_name:
  394. slot_fn = w_type.getdictvalue(space, attr)
  395. if slot_fn is None:
  396. return
  397. @cpython_api([PyObject, PyObject, PyObject], PyObject, header=header)
  398. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  399. def slot_func(space, w_self, w_arg1, w_arg2):
  400. return space.call_function(slot_fn, w_self, w_arg1, w_arg2)
  401. api_func = slot_func.api_func
  402. handled = True
  403. if handled:
  404. pass
  405. elif name == 'tp_setattro':
  406. setattr_fn = w_type.getdictvalue(space, '__setattr__')
  407. delattr_fn = w_type.getdictvalue(space, '__delattr__')
  408. if setattr_fn is None:
  409. return
  410. @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
  411. error=-1, header=header)
  412. @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,))
  413. def slot_tp_setattro(space, w_self, w_name, w_value):
  414. if w_value is not None:
  415. space.call_function(setattr_fn, w_self, w_name, w_value)
  416. else:
  417. space.call_function(delattr_fn, w_self, w_name)
  418. return 0
  419. api_func = slot_tp_setattro.api_func
  420. elif name == 'tp_getattro':
  421. getattr_fn = w_type.getdictvalue(space, '__getattribute__')
  422. if getattr_fn is None:
  423. return
  424. @cpython_api([PyObject, PyObject], PyObject, header=header)
  425. @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,))
  426. def slot_tp_getattro(space, w_self, w_name):
  427. return space.call_function(getattr_fn, w_self, w_name)
  428. api_func = slot_tp_getattro.api_func
  429. elif name == 'tp_call':
  430. call_fn = w_type.getdictvalue(space, '__call__')
  431. if call_fn is None:
  432. return
  433. @cpython_api([PyObject, PyObject, PyObject], PyObject, header=header)
  434. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  435. def slot_tp_call(space, w_self, w_args, w_kwds):
  436. args = Arguments(space, [w_self],
  437. w_stararg=w_args, w_starstararg=w_kwds)
  438. return space.call_args(call_fn, args)
  439. api_func = slot_tp_call.api_func
  440. elif name == 'tp_iternext':
  441. iternext_fn = w_type.getdictvalue(space, 'next')
  442. if iternext_fn is None:
  443. return
  444. @cpython_api([PyObject], PyObject, header=header)
  445. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  446. def slot_tp_iternext(space, w_self):
  447. try:
  448. return space.call_function(iternext_fn, w_self)
  449. except OperationError as e:
  450. if not e.match(space, space.w_StopIteration):
  451. raise
  452. return None
  453. api_func = slot_tp_iternext.api_func
  454. elif name == 'tp_init':
  455. init_fn = w_type.getdictvalue(space, '__init__')
  456. if init_fn is None:
  457. return
  458. @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1,
  459. header=header)
  460. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  461. def slot_tp_init(space, w_self, w_args, w_kwds):
  462. args = Arguments(space, [w_self],
  463. w_stararg=w_args, w_starstararg=w_kwds)
  464. space.call_args(init_fn, args)
  465. return 0
  466. api_func = slot_tp_init.api_func
  467. elif name == 'tp_new':
  468. new_fn = w_type.getdictvalue(space, '__new__')
  469. if new_fn is None:
  470. return
  471. @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, header=None)
  472. @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
  473. def slot_tp_new(space, w_self, w_args, w_kwds):
  474. args = Arguments(space, [w_self],
  475. w_stararg=w_args, w_starstararg=w_kwds)
  476. return space.call_args(space.get(new_fn, w_self), args)
  477. api_func = slot_tp_new.api_func
  478. else:
  479. # missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce
  480. # tp_as_sequence.c_sq_contains, tp_as_sequence.c_sq_length
  481. # richcmpfunc(s)
  482. return
  483. return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
  484. PyWrapperFlag_KEYWORDS = 1
  485. class TypeSlot:
  486. def __init__(self, method_name, slot_name, function, wrapper1, wrapper2, doc):
  487. self.method_name = method_name
  488. self.slot_name = slot_name
  489. self.slot_names = ("c_" + slot_name).split(".")
  490. self.slot_func = function
  491. self.wrapper_func = wrapper1
  492. self.wrapper_func_kwds = wrapper2
  493. self.doc = doc
  494. # adapted from typeobject.c
  495. def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
  496. if WRAPPER is None:
  497. wrapper = None
  498. else:
  499. wrapper = globals().get(WRAPPER, Ellipsis)
  500. # irregular interface, because of tp_getattr/tp_getattro confusion
  501. if NAME == "__getattr__":
  502. if SLOT == "tp_getattro":
  503. wrapper = wrap_getattro
  504. elif SLOT == "tp_getattr":
  505. wrapper = wrap_getattr
  506. else:
  507. assert False
  508. function = globals().get(FUNCTION, None)
  509. assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
  510. if FLAGS:
  511. if wrapper is Ellipsis:
  512. @func_renamer(WRAPPER)
  513. def wrapper(space, w_self, w_args, func, w_kwds):
  514. raise NotImplementedError("Wrapper for slot " + NAME)
  515. wrapper1 = None
  516. wrapper2 = wrapper
  517. else:
  518. if wrapper is Ellipsis:
  519. @func_renamer(WRAPPER)
  520. def wrapper(space, w_self, w_args, func):
  521. raise NotImplementedError("Wrapper for slot " + NAME)
  522. wrapper1 = wrapper
  523. wrapper2 = None
  524. return TypeSlot(NAME, SLOT, function, wrapper1, wrapper2, DOC)
  525. def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  526. return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)
  527. ETSLOT = TPSLOT
  528. def SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  529. return ETSLOT(NAME, "tp_as_sequence.c_" + SLOT, FUNCTION, WRAPPER, DOC)
  530. def MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  531. return ETSLOT(NAME, "tp_as_mapping.c_" + SLOT, FUNCTION, WRAPPER, DOC)
  532. def NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  533. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER, DOC)
  534. def UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  535. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER,
  536. "x." + NAME + "() <==> " + DOC)
  537. def IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
  538. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER,
  539. "x." + NAME + "(y) <==> x" + DOC + "y")
  540. def BINSLOT(NAME, SLOT, FUNCTION, DOC):
  541. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, "wrap_binaryfunc_l", \
  542. "x." + NAME + "(y) <==> x" + DOC + "y")
  543. def RBINSLOT(NAME, SLOT, FUNCTION, DOC):
  544. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, "wrap_binaryfunc_r", \
  545. "x." + NAME + "(y) <==> y" + DOC + "x")
  546. def BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC):
  547. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, "wrap_binaryfunc_l", \
  548. "x." + NAME + "(y) <==> " + DOC)
  549. def RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC):
  550. return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, "wrap_binaryfunc_r", \
  551. "x." + NAME + "(y) <==> " + DOC)
  552. """
  553. /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
  554. The logic in abstract.c always falls back to nb_add/nb_multiply in
  555. this case. Defining both the nb_* and the sq_* slots to call the
  556. user-defined methods has unexpected side-effects, as shown by
  557. test_descr.notimplemented() */
  558. """
  559. # Instructions for update:
  560. # Copy new slotdefs from typeobject.c
  561. # Remove comments and tabs
  562. # Done.
  563. slotdefs_str = r"""
  564. static slotdef slotdefs[] = {
  565. SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
  566. "x.__len__() <==> len(x)"),
  567. SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
  568. "x.__add__(y) <==> x+y"),
  569. SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
  570. "x.__mul__(n) <==> x*n"),
  571. SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
  572. "x.__rmul__(n) <==> n*x"),
  573. SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
  574. "x.__getitem__(y) <==> x[y]"),
  575. SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc,
  576. "x.__getslice__(i, j) <==> x[i:j]\n\
  577. \n\
  578. Use of negative indices is not supported."),
  579. SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
  580. "x.__setitem__(i, y) <==> x[i]=y"),
  581. SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
  582. "x.__delitem__(y) <==> del x[y]"),
  583. SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
  584. wrap_ssizessizeobjargproc,
  585. "x.__setslice__(i, j, y) <==> x[i:j]=y\n\
  586. \n\
  587. Use of negative indices is not supported."),
  588. SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice,
  589. "x.__delslice__(i, j) <==> del x[i:j]\n\
  590. \n\
  591. Use of negative indices is not supported."),
  592. SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
  593. "x.__contains__(y) <==> y in x"),
  594. SQSLOT("__iadd__", sq_inplace_concat, NULL,
  595. wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
  596. SQSLOT("__imul__", sq_inplace_repeat, NULL,
  597. wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
  598. MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
  599. "x.__len__() <==> len(x)"),
  600. MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
  601. wrap_binaryfunc,
  602. "x.__getitem__(y) <==> x[y]"),
  603. MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
  604. wrap_objobjargproc,
  605. "x.__setitem__(i, y) <==> x[i]=y"),
  606. MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
  607. wrap_delitem,
  608. "x.__delitem__(y) <==> del x[y]"),
  609. BINSLOT("__add__", nb_add, slot_nb_add,
  610. "+"),
  611. RBINSLOT("__radd__", nb_add, slot_nb_add,
  612. "+"),
  613. BINSLOT("__sub__", nb_subtract, slot_nb_subtract,
  614. "-"),
  615. RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract,
  616. "-"),
  617. BINSLOT("__mul__", nb_multiply, slot_nb_multiply,
  618. "*"),
  619. RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply,
  620. "*"),
  621. BINSLOT("__div__", nb_divide, slot_nb_divide,
  622. "/"),
  623. RBINSLOT("__rdiv__", nb_divide, slot_nb_divide,
  624. "/"),
  625. BINSLOT("__mod__", nb_remainder, slot_nb_remainder,
  626. "%"),
  627. RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder,
  628. "%"),
  629. BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod,
  630. "divmod(x, y)"),
  631. RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod,
  632. "divmod(y, x)"),
  633. NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc,
  634. "x.__pow__(y[, z]) <==> pow(x, y[, z])"),
  635. NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r,
  636. "y.__rpow__(x[, z]) <==> pow(x, y[, z])"),
  637. UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"),
  638. UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"),
  639. UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc,
  640. "abs(x)"),
  641. UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred,
  642. "x != 0"),
  643. UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"),
  644. BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"),
  645. RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"),
  646. BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"),
  647. RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"),
  648. BINSLOT("__and__", nb_and, slot_nb_and, "&"),
  649. RBINSLOT("__rand__", nb_and, slot_nb_and, "&"),
  650. BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"),
  651. RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"),
  652. BINSLOT("__or__", nb_or, slot_nb_or, "|"),
  653. RBINSLOT("__ror__", nb_or, slot_nb_or, "|"),
  654. NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc,
  655. "x.__coerce__(y) <==> coerce(x, y)"),
  656. UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc,
  657. "int(x)"),
  658. UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc,
  659. "long(x)"),
  660. UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
  661. "float(x)"),
  662. UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc,
  663. "oct(x)"),
  664. UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
  665. "hex(x)"),
  666. NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
  667. "x[y:z] <==> x[y.__index__():z.__index__()]"),
  668. IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
  669. wrap_binaryfunc, "+"),
  670. IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
  671. wrap_binaryfunc, "-"),
  672. IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
  673. wrap_binaryfunc, "*"),
  674. IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
  675. wrap_binaryfunc, "/"),
  676. IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
  677. wrap_binaryfunc, "%"),
  678. IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
  679. wrap_binaryfunc, "**"),
  680. IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
  681. wrap_binaryfunc, "<<"),
  682. IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
  683. wrap_binaryfunc, ">>"),
  684. IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
  685. wrap_binaryfunc, "&"),
  686. IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
  687. wrap_binaryfunc, "^"),
  688. IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
  689. wrap_binaryfunc, "|"),
  690. BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
  691. RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
  692. BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"),
  693. RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"),
  694. IBSLOT("__ifloordiv__", nb_inplace_floor_divide,
  695. slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
  696. IBSLOT("__itruediv__", nb_inplace_true_divide,
  697. slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
  698. TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
  699. "x.__str__() <==> str(x)"),
  700. TPSLOT("__str__", tp_print, NULL, NULL, ""),
  701. TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
  702. "x.__repr__() <==> repr(x)"),
  703. TPSLOT("__repr__", tp_print, NULL, NULL, ""),
  704. TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc,
  705. "x.__cmp__(y) <==> cmp(x,y)"),
  706. TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
  707. "x.__hash__() <==> hash(x)"),
  708. FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
  709. "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
  710. TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
  711. wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
  712. TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
  713. TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
  714. TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
  715. TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
  716. "x.__setattr__('name', value) <==> x.name = value"),
  717. TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
  718. TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
  719. "x.__delattr__('name') <==> del x.name"),
  720. TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
  721. TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
  722. "x.__lt__(y) <==> x<y"),
  723. TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
  724. "x.__le__(y) <==> x<=y"),
  725. TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
  726. "x.__eq__(y) <==> x==y"),
  727. TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
  728. "x.__ne__(y) <==> x!=y"),
  729. TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
  730. "x.__gt__(y) <==> x>y"),
  731. TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
  732. "x.__ge__(y) <==> x>=y"),
  733. TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
  734. "x.__iter__() <==> iter(x)"),
  735. TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next,
  736. "x.next() -> the next value, or raise StopIteration"),
  737. TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
  738. "descr.__get__(obj[, type]) -> value"),
  739. TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
  740. "descr.__set__(obj, value)"),
  741. TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
  742. wrap_descr_delete, "descr.__delete__(obj)"),
  743. FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
  744. "x.__init__(...) initializes x; "
  745. "see x.__class__.__doc__ for signature",
  746. PyWrapperFlag_KEYWORDS),
  747. TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
  748. TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
  749. {NULL}
  750. };
  751. """
  752. # Convert the above string into python code
  753. slotdef_replacements = (
  754. ("\s+", " "), # all on one line
  755. ("static [^{]*{", "("), # remove first line...
  756. ("};", ")"), # ...last line...
  757. ("{NULL}", ""), # ...and sentinel
  758. # add quotes around function name, slot name, and wrapper name
  759. (r"(?P<start> +..SLOT\([^,]*, )(?P<fname>[^,]*), (?P<slotcname>[^,]*), (?P<wname>[^,]*)", r"\g<start>'\g<fname>', '\g<slotcname>', '\g<wname>'"),
  760. (r"(?P<start> *R?[^ ]{3}SLOT(NOTINFIX)?\([^,]*, )(?P<fname>[^,]*), (?P<slotcname>[^,]*)", r"\g<start>'\g<fname>', '\g<slotcname>'"),
  761. ("'NULL'", "None"), # but NULL becomes None
  762. ("\(wrapperfunc\)", ""), # casts are not needed in python tuples
  763. ("\),", "),\n"), # add newlines again
  764. )
  765. for regex, repl in slotdef_replacements:
  766. slotdefs_str = re.sub(regex, repl, slotdefs_str)
  767. slotdefs = eval(slotdefs_str)
  768. # PyPy addition
  769. slotdefs += (
  770. TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""),
  771. )
  772. # partial sort to solve some slot conflicts:
  773. # Number slots before Mapping slots before Sequence slots.
  774. # These are the only conflicts between __name__ methods
  775. def slotdef_sort_key(slotdef):
  776. if slotdef.slot_name.startswith('tp_as_number'):
  777. return 1
  778. if slotdef.slot_name.startswith('tp_as_mapping'):
  779. return 2
  780. if slotdef.slot_name.startswith('tp_as_sequence'):
  781. return 3
  782. return 0
  783. slotdefs = sorted(slotdefs, key=slotdef_sort_key)
  784. slotdefs_for_tp_slots = unrolling_iterable(
  785. [(x.method_name, x.slot_name, x.slot_names, x.slot_func)
  786. for x in slotdefs])
  787. slotdefs_for_wrappers = unrolling_iterable(
  788. [(x.method_name, x.slot_names, x.wrapper_func, x.wrapper_func_kwds, x.doc)
  789. for x in slotdefs])
  790. if __name__ == "__main__":
  791. print slotdefs_str